考虑空位的移动,合法的按钮只有两种:要么是排列,要么只有两个数相同。对于前者,空位只能沿着排列移动,对于后者,是x → a , x → b x\to a,x\to b x → a , x → b 
如果空位可以从u u u v v v u → v u\to v u → v c c c a a a b b b 
对于固定的图,这是个很经典的问题,先缩点,拓扑排序时用 bitset 维护即可  ,参考 洛谷 P10480 可达性统计 。
加上只允许使用前c c c 离线询问  ,不断加边。 每加一组边,重新缩点并拓扑排序 。
注意图比较特殊,要么是环(这样缩点之后就没有边了),要么是两条边,每次只有n + l n+l n + l l l l Θ ( l ( n + l ) log  n ) \Theta\big(l(n+l) \log n\big) Θ ( l ( n + l ) log  n ) 
对多次 Tarjan 不熟,所以缩点之后又套了个并查集,应该是不需要的。
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 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 int  read ()      char  u, v;     cin >> u >> v;     return  (u - 48 ) * 50  + v - 48 ; } const  int  N = 2008 ;void  eachT ()      int  n, l, q;     cin >> n >> l >> q;     vector<vector<pair<int , int >>> E (l + 1 );     for  (int  i = 1 ; i <= l; ++i) {         vector<int > t (n + 1 ) , cnt (n + 1 )  ;         for  (int  j = 1 ; j <= n; ++j) {             t[j] = read ();             cnt[t[j]] += 1 ;         }         int  mul = -1 , zero = -1 , ok = 1 ;         for  (int  j = 1 ; j <= n; ++j) {             if  (cnt[j] == 2 ) {                 if  (mul == -1 ) mul = j;                 else  ok = 0 ;             }             if  (cnt[j] == 0 ) {                 if  (zero == -1 ) zero = j;                 else  ok = 0 ;             }         }         if  (!ok) continue ;         if  (mul == -1 ) {             for  (int  j = 1 ; j <= n; ++j) {                 E[i].emplace_back (j, t[j]);             }         }         else  for  (int  j = 1 ; j <= n; ++j) {             if  (cnt[t[j]] == 2 ) {                 E[i].emplace_back (j, zero);             }         }     }     vector<vector<tuple<int , int , int >>> que (l + 1 );     for  (int  i = 0 ; i < q; ++i) {         int  a = read (), b = read (), c = read ();         que[c].emplace_back (a, b, i);     }     vector<int > ans (q)  ;     vector<vector<int >> adj (n + 1 );     DSU dsu (n)  ;     for  (int  c = 0 ; c <= l; ++c) {         for  (auto & [u, v] : E[c]) {             adj[dsu.find (v)].push_back (dsu.find (u));         }                  vector<int > dfn (n + 1 ) , low (n + 1 ) , fa (n + 1 )  ;         int  unix = 0 ;         stack<int > stk;         auto  dfs = [&](auto && self, int  u) -> void  {             dfn[u] = low[u] = ++unix;             stk.push (u);             for  (auto & v : adj[u]) {                 if  (!dfn[v]) self (self, v), low[u] = min (low[u], low[v]);                 else  if  (!fa[v]) low[u] = min (low[u], dfn[v]);             }             if  (low[u] == dfn[u]) {                 int  v;                 do  {                     v = stk.top (); stk.pop ();                     fa[v] = u;                 } while  (v != u);             }         };         for  (int  u = 1 ; u <= n; ++u) {             if  (!dfn[u]) dfs (dfs, u);         }         vector<vector<int >> tadj (n + 1 );         for  (int  u = 1 ; u <= n; ++u) {             for  (auto & v : adj[u]) {                 if  (fa[u] != fa[v]) tadj[fa[u]].push_back (fa[v]);             }         }         for  (int  u = 1 ; u <= n; ++u) {             dsu.uno (fa[u], u);             adj[u] = tadj[u];             adj[u].erase (unique (adj[u].begin (), adj[u].end ()), adj[u].end ());         }         vector<int > deg (n + 1 )  ;         vector<bitset<N>> dp (n + 1 );         for  (int  u = 1 ; u <= n; ++u) {             for  (auto  v : adj[u]) {                 deg[v] += 1 ;             }         }         queue<int > Q;         for  (int  u = 1 ; u <= n; ++u) {             dp[u][u] = 1 ;             if  (!deg[u]) Q.push (u);         }         while  (!Q.empty ()) {             int  u = Q.front (); Q.pop ();             for  (auto  to : adj[u]) {                 deg[to] -= 1 ;                 dp[to] |= dp[u];                 if  (!deg[to]) Q.push (to);             }         }         for  (auto & [a, b, id] : que[c]) {             if  (dp[dsu.find (a)][dsu.find (b)] == 1 ) ans[id] = 1 ;         }     }     for  (int  i = 0 ; i < q; ++i) {         cout << ans[i];     }     cout << '\n' ; } 
UPD:如果强制在线也是可以做的。
把按钮编号看做权值,预处理从a a a b b b n n n 
但全源最短路的复杂度是Θ ( m n ) = Θ ( n 3 ) \Theta(mn)=\Theta(n^{3}) Θ ( m n ) = Θ ( n 3 ) k k k k − 1 k-1 k − 1 n n n n 2 n^2 n 2 n − 1 n-1 n − 1 2 ( n − 1 ) + 2 l 2(n-1)+2l 2 ( n − 1 ) + 2 l 
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 void  eachT ()      int  n, l, q;     cin >> n >> l >> q;     vector<vector<pair<int , int >>> E (n + 1 );     DSU dsu (n)  ;     for  (int  i = 1 ; i <= l; ++i) {         vector<int > t (n + 1 ) , cnt (n + 1 )  ;         for  (int  j = 1 ; j <= n; ++j) {             t[j] = read ();             cnt[t[j]] += 1 ;         }         int  mul = -1 , zero = -1 , ok = 1 ;         for  (int  j = 1 ; j <= n; ++j) {             if  (cnt[j] == 2 ) {                 if  (mul == -1 ) mul = j;                 else  ok = 0 ;             }             if  (cnt[j] == 0 ) {                 if  (zero == -1 ) zero = j;                 else  ok = 0 ;             }         }         if  (!ok) continue ;         if  (mul == -1 ) {             for  (int  j = 1 ; j <= n; ++j) {                 if  (dsu.uno (j, t[j])) {                     E[j].emplace_back (i, t[j]);                     E[t[j]].emplace_back (i, j);                 }             }         }         else  for  (int  j = 1 ; j <= n; ++j) {             if  (cnt[t[j]] == 2 ) {                 E[j].emplace_back (i, zero);             }         }     }     vector dis (n + 1 , vector<int >(n + 1 , 0x3f3f3f3f ))  ;     for  (int  s = 1 ; s <= n; ++s) {         vector<int > vis (n + 1 )  ;         dis[s][s] = 0 ;         priority_queue<pair<int , int >, vector<pair<int , int >>, greater<>> Q;         Q.push ({ 0 , s });         while  (!Q.empty ()) {             auto  [d, u] = Q.top (); Q.pop ();             if  (vis[u]) continue ;             vis[u] = 1 ;             for  (auto & [w, v] : E[u]) {                 if  (dis[s][v] > max (dis[s][u], w)) {                     dis[s][v] = max (dis[s][u], w);                     Q.push ({ dis[s][v], v });                 }             }         }     }     while  (q--) {         int  a = read (), b = read (), c = read ();         cout << (dis[a][b] <= c ? '1'  : '0' );     }     cout << '\n' ; } 
我们画一个n × n n\times n n × n i i i j j j 1 1 1 l i ⩽ j ⩽ r i l_{i} \leqslant j \leqslant r_{i} l i  ⩽ j ⩽ r i  p i p_{i} p i  j j j 
熟知,黑白棋盘,可选择交换两行或交换两列,问能否在若干次操作后,使棋盘的主对角线均为黑色,可以用二分图的匈牙利算法解决。对于本题,如果能找到一些1 1 1 
上面写的没用,一方面时间复杂度不允许,另一方面,我们只关心奇偶性,不必求出具体方案数。
但是上面的思路启发我们 从01 \mathtt{01} 0 1  。
考虑这几种情形:
[ 1 , 1 ] , [ 2 , 2 ] [1,1],[2,2] [ 1 , 1 ] , [ 2 , 2 ] [ 1 , 2 ] , [ 2 , 2 ] [1,2],[2,2] [ 1 , 2 ] , [ 2 , 2 ] [ 1 , 2 ] , [ 1 , 2 ] [1,2],[1,2] [ 1 , 2 ] , [ 1 , 2 ] 对于第三个情形,这两个[ 1 , 2 ] [1,2] [ 1 , 2 ] [ 1 , 2 ] [1,2] [ 1 , 2 ] 2 2 2 2 2 2 [ 1 , 2 ] [1,2] [ 1 , 2 ] [ 1 , 1 ] [1,1] [ 1 , 1 ] [ 1 , 1 ] , [ 2 , 2 ] [1,1],[2,2] [ 1 , 1 ] , [ 2 , 2 ] 
所以猜测,这些区间任意相减,答案奇偶性不变。
可以确定的是,单位阵的答案是奇数,而[ 1 0 0 0 1 0 0 0 0 ] \begin{bmatrix}1&0&0\\0&1&0\\0&0&0\end{bmatrix} ⎣ ⎢ ⎡  1 0 0  0 1 0  0 0 0  ⎦ ⎥ ⎤  
那么结论就是:当前仅当这个矩阵与单位阵等价时,答案为奇数 。
模拟这个化行阶梯矩阵的过程即可:
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 void  eachT ()      int  n;     cin >> n;     vector<vector<int >> v (n + 2 );     for  (int  i = 0 ; i < n; ++i) {         int  l, r;         cin >> l >> r;         v[l].push_back (r);     }     bool  ok = 1 ;     for  (int  l = 1 ; l <= n; ++l) {         if  (v[l].empty ()) {             ok = 0 ;             break ;         }         sort (v[l].begin (), v[l].end (), greater<>());         int  big = v[l][0 ];         for  (int  j = 1 ; j < v[l].size (); ++j) {             if  (v[l][j - 1 ] == v[l][j]) {                 ok = 0 ;                 break ;             }             int  r = v[l][j];             v[r + 1 ].push_back (big);         }         if  (ok == 0 ) break ;     }     cout << ok << '\n' ; } 
上面代码的复杂度不定,最坏可能到n 2 n^{2} n 2 
环可以用并查集判断,时间复杂度Θ ( n ) \Theta(n) Θ ( n ) 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 void  eachT ()      int  n;     cin >> n;     DSU dsu (n)  ;     bool  ok = 1 ;     for  (int  i = 0 ; i < n; ++i) {         int  l, r;         cin >> l >> r;         l--;         if  (!dsu.uno (l, r)) {             ok = 0 ;         }     }     cout << ok << '\n' ; } 
先看两个很经典的题 洛谷 P2824 排序 、 AGC006D. Median Pyramid Hard 。
类似的思路,二分答案为x x x x x x 1 1 1 − 1 -1 − 1 0 0 0 
时间复杂度Θ ( n 2 log  n ) \Theta(n^{2}\log n) Θ ( n 2 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 const  int  N = 2008 ;int  arr[N], sa[N];int  b[N][N], sb[N][N];void  eachT ()      int  n;     cin >> n;     for  (int  i = 1 ; i <= n; ++i) {         cin >> arr[i];     }     auto  check = [&](int  x) {         sa[0 ] = 0 ;         for  (int  i = 1 ; i <= n; ++i) {             int  a = arr[i] <= x ? 1  : -1 ;             sa[i] = sa[i - 1 ] + a;         }         for  (int  i = 1 ; i <= n; ++i) {             for  (int  j = i; j <= n; ++j) {                 b[i][j] = sa[j] - sa[i - 1 ] >= 0  ? 1  : -1 ;             }         }         for  (int  i = 1 ; i <= n; ++i) {             for  (int  j = 1 ; j <= n; ++j) {                 sb[i][j] = sb[i - 1 ][j] + sb[i][j - 1 ] - sb[i - 1 ][j - 1 ] + b[i][j];             }         }         int  sum = 0 ;         for  (int  i = 1 ; i <= n; ++i) {             for  (int  j = i; j <= n; ++j) {                 int  c = sb[j][j] - sb[i - 1 ][j] - sb[j][i - 1 ] + sb[i - 1 ][i - 1 ] >= 0  ? 1  : -1 ;                 sum += c;             }         }         return  sum >= 0 ;     };     int  l = 0 , r = 1e9  + 1 ;     while  (l <= r) {         int  mid = l + r >> 1 ;         if  (check (mid)) r = mid - 1 ;         else  l = mid + 1 ;     }     cout << l << '\n' ; } 
基于贪心,从最小的数开始,将每个数a i a_{i} a i  a i a_{i} a i  a i a_{i} a i  f i f_{i} f i  
为了记录能操作几次,倒着看这个过程,就有ans(i)  = ans  ( f i ) + 1 \operatorname{ans(i)}=\operatorname{ans}(f_{i})+1 a n s ( i ) = a n s ( f i  ) + 1 
「左侧最近的比a i a_{i} a i  
时间复杂度Θ ( n log  n ) \Theta(n\log n) Θ ( n 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 void  eachT ()      int  n;     cin >> n;     vector<int > a (n)  ;     vector<int > alls;     vector<vector<int >> vec (n);       for  (int  i = 0 ; i < n; ++i) {         cin >> a[i];         alls.push_back (a[i]);     }          sort (alls.begin (), alls.end ());     unique (alls.begin (), alls.end ());     for  (int  i = 0 ; i < n; ++i) {         a[i] = lower_bound (alls.begin (), alls.end (), a[i]) - alls.begin ();         vec[a[i]].push_back (i);     }     vector<int > lst (n) , nxt (n)  ;     vector<int > stk;     for  (int  i = 0 ; i < n; ++i) {         while  (!stk.empty () && a[i] >= a[stk.back ()]) {             stk.pop_back ();         }         lst[i] = stk.empty () ? -1  : stk.back ();         stk.push_back (i);     }     stk.clear ();     for  (int  i = n - 1 ; i >= 0 ; --i) {         while  (!stk.empty () && a[i] >= a[stk.back ()]) {             stk.pop_back ();         }         nxt[i] = stk.empty () ? -1  : stk.back ();         stk.push_back (i);     }     vector<int > ans (n)  ;     for  (int  j = n - 1 ; j >= 0 ; --j) {         for  (auto & i : vec[j]) {             int  fa;             if  (nxt[i] == -1  && lst[i] == -1 ) continue ;             if  (nxt[i] == -1 ) fa = lst[i];             else  if  (lst[i] == -1 ) fa = nxt[i];             else  if  (a[nxt[i]] > a[lst[i]]) fa = lst[i];             else  fa = nxt[i];             ans[i] = ans[fa] + 1 ;         }     }     ll anss = 0 ;     for  (int  i = 0 ; i < n; ++i) {         anss += ans[i];     }     cout << anss << '\n' ; } 
蛮有意思的题目。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 void  eachT ()      int  me;     cin >> me;     int  rk = 1 ;     for  (int  i = 1 ; i < 32 ; ++i) {         int  x;         cin >> x;         if  (x > me) ++rk;     }     int  ans;     if  (rk == 1 ) ans = 1 ;     else  if  (rk <= 5 ) ans = 2 ;     else  if  (rk <= 19 ) ans = 4 ;     else  if  (rk <= 26 ) ans = 8 ;     else  if  (rk <= 30 ) ans = 16 ;     else  ans = 32 ;     cout << ans << '\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 void  eachT ()      int  n;     cin >> n;     map<string, vector<string>> a;     while  (n--) {         string name, id, op;         cin >> name >> id >> op;         if  (op[0 ] == 'a' ) {             a[id].push_back (name);         }     }     string mx = "" ;     for  (auto & [k, vec] : a) {         sort (vec.begin (), vec.end ());         vec.erase (unique (vec.begin (), vec.end ()), vec.end ());         if  (a[mx].size () < a[k].size ()) {             mx = k;         }     }     cout << mx << '\n' ; }