矩形里最长的两段垂直线段是最大正方形的对角线。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include  <iostream>  #include  <algorithm>  #include  <vector>  using  namespace  std;using  ll = long  long ;int  main ()      ios::sync_with_stdio (false );     cin.tie (nullptr );     int  t;     cin >> t;     while  (t--) {         int  x, y, k;         cin >> x >> y >> k;         int  s = min (x, y);         cout << "0 0 "  << s << " "  << s << "\n" ;         cout << "0 "  << s << " "  << s << " 0\n" ;     }     return  0 ; } 
对于偶数,有唯一解,即是a 2 k − a 2 k − 1 a_{2k}-a_{2k-1} a 2 k  − a 2 k − 1  k k k a 2 k − a 2 k − 1 a_{2k}-a_{2k-1} a 2 k  − a 2 k − 1  a 2 − a 1 , a 4 − a 3 , … , a 2 k − 2 − a 2 k − 3 , a 2 k + 1 − a 2 k , … , a n − a n − 1 a_{2}-a_{1},a_{4}-a_{3},\dots ,a_{2k-2}-a_{2k-3},a_{2k+1}-a_{2k},\dots ,a_{n}-a_{n-1} a 2  − a 1  , a 4  − a 3  , … , a 2 k − 2  − a 2 k − 3  , a 2 k + 1  − a 2 k  , … , a n  − a n − 1  k k k 
时间复杂度Θ ( n 2 ) \Theta(n^{2}) Θ ( n 2 ) 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include  <iostream>  #include  <algorithm>  #include  <vector>  using  namespace  std;using  ll = long  long ;int  main ()      ios::sync_with_stdio (false );     cin.tie (nullptr );     int  t;     cin >> t;     while  (t--) {         int  n;         cin >> n;         vector<ll> a (n)  ;         for  (int  i = 0 ; i < n; i++) {             cin >> a[i];         }         ll ans = 8e18 ;         if  (n % 2  == 0 ) {             ll mx = 0 ;             for  (int  i = 0 ; i + 1  < n; i += 2 ) {                 mx = max (mx, a[i + 1 ] - a[i]);             }             ans = mx;         } else  {             for  (int  j = 0 ; j < n; j += 2 ) {                 ll mx = 0 ;                 for  (int  i = 0 ; i + 1  < n; i += 2 ) {                     if  (i == j) i++;                     mx = max (mx, a[i + 1 ] - a[i]);                 }                 ans = min (ans, mx);             }         }         ans = max (ans, 1ll );         cout << ans << "\n" ;     }     return  0 ; } 
倒着循环。
如果是 1,这个可能不需要花钱,放到一个 deque 里表示暂时不花钱;如果是 0,必须和之前(也就是下标靠后的)的一起买,从 deque 取出一个不花钱的商品,这两个一起买,价格是这一位的价格,如果 deque 为空,那这个商品必定花钱(和之前一起买)。
如果最后 deque 非空,选择其中较小的一半购买。
事实上 deque 中有价值的部分是它的大小,所以直接开个变量 siz 就行。
时间复杂度Θ ( n ) \Theta(n) Θ ( n ) 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include  <iostream>  #include  <algorithm>  #include  <vector>  #include  <deque>  using  namespace  std;using  ll = long  long ;int  main ()      ios::sync_with_stdio (false );     cin.tie (nullptr );     int  t;     cin >> t;     while  (t--) {         int  n;         cin >> n;         string s;         cin >> s;         s = ' '  + s;         deque<int > Q;         ll ans = 0 ;         for  (int  i = n; i; i--) {             if  (s[i] == '1' ) {                 Q.push_back (i);             } else  if  (Q.empty ()) {                 ans += i;             } else  {                 Q.pop_front ();                 ans += i;             }         }         while  (!Q.empty ()) {             ans += Q.back ();             Q.pop_back ();             if  (!Q.empty ()) Q.pop_front ();         }         cout << ans << "\n" ;     }     return  0 ; } 
问题在于怎么算s ( m , m ) + s ( m , m + 1 ) + ⋯ + s ( m , t ) s(m,m)+s(m,m+1)+\dots+s(m,t) s ( m , m ) + s ( m , m + 1 ) + ⋯ + s ( m , t ) 
我们先算s ( m , m ) + s ( m , m + 1 ) + ⋯ + s ( m , n ) s(m,m)+s(m,m+1)+\dots+s(m,n) s ( m , m ) + s ( m , m + 1 ) + ⋯ + s ( m , n ) ∑ i = m n ( n − i + 1 ) a i \sum \limits_{i=m}^{n}(n-i+1)a_{i} i = m ∑ n  ( n − i + 1 ) a i  ( n − i + 1 ) a i (n-i+1)a_{i} ( n − i + 1 ) a i  s ( m , m ) + s ( m , m + 1 ) + ⋯ + s ( m , t ) s(m,m)+s(m,m+1)+\dots+s(m,t) s ( m , m ) + s ( m , m + 1 ) + ⋯ + s ( m , t ) ∑ i = m t ( t − i + 1 ) a i \sum \limits_{i=m}^{t}(t-i+1)a_{i} i = m ∑ t  ( t − i + 1 ) a i  ∑ i = m n ( n − i + 1 ) a i − ∑ i = t + 1 n ( n − i + 1 ) a i − ( n − t ) ∑ i = m t a i \sum \limits_{i=m}^{n}(n-i+1)a_{i}-\sum \limits_{i=t+1}^{n}(n-i+1)a_{i}-(n-t) \sum\limits_{i=m}^{t}a_{i} i = m ∑ n  ( n − i + 1 ) a i  − i = t + 1 ∑ n  ( n − i + 1 ) a i  − ( n − t ) i = m ∑ t  a i  
然后把b b b i i i n − i + 1 n-i+1 n − i + 1 
时间复杂度Θ ( n + q log  n ) \Theta(n+q\log n) Θ ( n + q log  n ) 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 #include  <iostream>  #include  <algorithm>  #include  <vector>  using  namespace  std;using  ll = long  long ;int  main ()      ios::sync_with_stdio (false );     cin.tie (nullptr );     int  n;     cin >> n;     vector<ll> sa (n + 1 ) , ia (n) , sufia (n + 1 ) , pre (n + 1 )  ;     for  (int  i = 0 ; i < n; i++) {         int  x;         cin >> x;         sa[i + 1 ] = sa[i] + x;         ia[i] = (n - i) * x;     }     for  (int  i = n - 1 ; i >= 0 ; i--) {         sufia[i] = sufia[i + 1 ] + ia[i];     }     auto  calia = [&](ll m, ll t) {         return  sufia[m] - sufia[t] - (n - t) * (sa[t] - sa[m]);     };     for  (int  i = 0 ; i < n; i++) {         pre[i + 1 ] = pre[i] + calia (i, n);     }     auto  cal = [&](ll m) {         ll l = 0 , r = n;         while  (l <= r) {             ll mid = l + r >> 1 ;             if  ((1ll  * (n + n - (mid - 1 )) * mid / 2 ) <= m) {                 l = mid + 1 ;             } else  {                 r = mid - 1 ;             }         }         ll mid = r;         ll id = m - (1ll  * (n + n - (mid - 1 )) * mid / 2 );         return  pre[mid] + calia (mid, mid + id);     };     int  q;     cin >> q;     while  (q--) {         ll l, r;         cin >> l >> r;         l--;         cout << (cal (r) - cal (l)) << "\n" ;     }     return  0 ; } 
每个东西有选或不选两种状态,而且每个东西都状态确定,价值也相应确定。
赛时考虑过 DP,但每个数之间关系很强,很难转移;考虑过字典树,但本题每个二进制位是独立的,字典树强加了一个顺序;考虑过连边跑最短路,但这种方法适用于二者的关系,而不是很多数之间的关系。
画出了 01 矩阵(行是数,列是二进制位),很像二分图,又不是最大匹配,所以想换一种连边方式跑最大流。
选择一个二进制位,损失为 1,不选一个数,损失为 1,理想情况是 n,求最小损失。
从源点向每个数连边权为 1 的边,从每个二进制位向汇点连边权为 1 的边,对于每个数,如果某个二进制位为 1,则由这个数向二进制位连边权为无穷的边。则最小损失是最小割。
答案为理想情况减去最小损失。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 #include  <bits/stdc++.h>  using  namespace  std;using  ll = long  long ;struct  MaxFlow  {    vector<vector<array<int , 3>>> E;     vector<int > level, curr;     MaxFlow (int  n) : E (n), level (n), curr (n) {}     void  add (int  u, int  v, int  w)           E[u].push_back ({ w, v, int (E[v].size ()) });         E[v].push_back ({ 0 , u, int (E[u].size ()) - 1  });     }     bool  bfs (int  s, int  t)           queue<int > q;         fill (level.begin (), level.end (), 0 );         fill (curr.begin (), curr.end (), 0 );         level[s] = 1 ;         q.push (s);         while  (!q.empty ()) {             int  u = q.front ();             q.pop ();             for  (auto & [w, v, id] : E[u]) {                 if  (w && !level[v]) {                     level[v] = level[u] + 1 ;                     q.push (v);                 }             }         }         return  level[t] > 0 ;     }     int  dfs (int  u, int  t, int  maxf)           if  (u == t) return  maxf;         for  (int & i = curr[u]; i < E[u].size (); i++) {             auto & [w, v, id] = E[u][i];             if  (w && (level[v] == level[u] + 1 )) {                 int  f = dfs (v, t, min (maxf, w));                 if  (f) {                     w -= f;                     E[v][id][0 ] += f;                     curr[u] = i;                     return  f;                 }             }         }         return  0 ;     }     int  dinic (int  s, int  t)           int  ans = 0 ;         while  (bfs (s, t)) {             while  (int  f = dfs (s, t, 1e9 )) {                 ans += f;             }         }         return  ans;     } }; int  main ()      ios::sync_with_stdio (false );     cin.tie (nullptr );     int  t;     cin >> t;     while  (t--) {         int  n;         cin >> n;         MaxFlow G (n + 62 )  ;         int  s = n + 60 , t = n + 61 ;         for  (int  i = 0 ; i < n; i++) {             ll x;             cin >> x;             G.add (s, i, 1 );             for  (int  bit = 0 ; bit < 60 ; bit++) {                 if  (x >> bit & 1 ) {                     G.add (i, n + bit, 1e9 );                 }             }         }                  for  (int  bit = 0 ; bit < 60 ; bit++) {             G.add (n + bit, t, 1 );         }         cout << n - G.dinic (s, t) << "\n" ;         }     return  0 ; }