其实很多时候并不是完全靠“灵机一动”,一些trick是可以积累的
题目来源主要是OpenTrain,附上个人难度评价
不断更新
OpenTrain 006254B ($Black and White$,$2014ICPC$北京) 【medium-easy】
Problem B. Black And White Input file: standard input Output file: standard output Time limit: 1 second Memory limit: 512 mebibytes In this problem, you have to solve the 4-color problem. Hey, I’m just joking. You are asked to solve a similar problem: Color an N × M chessboard with K colors numbered from 1 to K such that no two adjacent cells have the same color (two cells are adjacent if they share an edge). The i-th color should be used in exactly c_i cells. Matt hopes you can tell him a possible coloring. Input The first line contains only one integer T (1 ≤ T ≤ 5000), which indicates the number of test cases. For each test case, the first line contains three integers: N, M, K (0 < N, M ≤ 5, 0 < K ≤ N × M). The second line contains K integers ci (ci > 0), denoting the number of cells where the i-th color should be used. It’s guaranteed that c1 + c2 + · · · + cK = N × M. Output For each test case, the first line contains “Case #x: where x is the case number (starting from 1). In the second line, output “NO” if there is no coloring satisfying the requirements. Otherwise, output “YES” in one line. Each of the following N lines contains M numbers seperated by single whitespace, denoting the color of the cells. If there are multiple solutions, output any of them. Example standard input 4 1 5 2 4 1 3 3 4 1 2 2 4 2 3 3 2 2 2 3 2 3 2 2 2 standard output Case #1: NO Case #2: YES 4 3 4 2 1 2 4 3 4 Case #3: YES 1 2 3 2 3 1 Case #4: YES 1 2 2 3 3 1
很多构造题目都会强调一些奇怪的条件,比如xxx超过$frac{n}{2}$(例如$2019ECFinal$的H题)
虽然这题没有强调,但是也可以考虑 超过/未超过一半 的情况,在这题中指的是最大的$c_i$
比较容易看出来的是,应该按奇偶位分别考虑
假如有$c_i>lfloorfrac{N imes M+1}{2} floor$,那么显然无法构造
称第二大的为$c_j$,那么
如果$c_i+c_jleqlfloorfrac{N imes M+1}{2} floor$,则所有颜色按照$c$从大到小先涂偶位、再涂奇位;显然同一种颜色不可能相连
如果$c_i+c_j>lfloorfrac{N imes M+1}{2} floor$,则可以$c_i$正着涂偶位、$c_j$倒着涂奇位;容易证明这样涂一遍后能让剩余的偶位、奇位间分别不相连
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef pair<int,int> pii; const int N=10; int n,m,k; int c[N*N]; inline bool cmp(int x,int y) { return c[x]>c[y]; } int ord[N*N]; int cnt; pii pos[N*N]; int ans[N][N]; int main() { int T; scanf("%d",&T); for(int kase=1;kase<=T;kase++) { scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=k;i++) scanf("%d",&c[i]),ord[i]=i; ord[k+1]=0; sort(ord+1,ord+k+1,cmp); printf("Case #%d: ",kase); if(c[ord[1]]>(n*m+1)/2) { printf("NO "); continue; } printf("YES "); bool flag=(n<m); if(flag) swap(n,m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) ans[i][j]=0; cnt=0; for(int i=1;i<=n;i++) for(int j=(i%2==1?1:2);j<=m;j+=2) pos[++cnt]=pii(i,j); for(int i=1;i<=n;i++) for(int j=(i%2==1?2:1);j<=m;j+=2) pos[++cnt]=pii(i,j); if(c[ord[1]]+c[ord[2]]<=(n*m+1)/2) { cnt=0; for(int i=1;i<=k;i++) for(int j=1;j<=c[ord[i]];j++) { ++cnt; ans[pos[cnt].first][pos[cnt].second]=ord[i]; } } else { int it=0; for(int i=1;i<=c[ord[1]];i++) { ++it; ans[pos[it].first][pos[it].second]=ord[1]; } it=n*m+1; for(int i=1;i<=c[ord[2]];i++) { --it; ans[pos[it].first][pos[it].second]=ord[2]; } it=0; for(int i=3;i<=k;i++) for(int j=1;j<=c[ord[i]];j++) { ++it; while(ans[pos[it].first][pos[it].second]!=0) ++it; ans[pos[it].first][pos[it].second]=ord[i]; } } if(flag) swap(n,m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) printf("%d",flag?ans[j][i]:ans[i][j]),putchar(j==m?' ':' '); } return 0; }
OpenTrain 005021K ($Kids Designing Kids$,$NEERC2016$) 【medium-easy】
Problem K. Kids Designing Kids Input file: kids.in Output file: kids.out Kevin and Kimberly have freckles on their foreheads. They both drew their freckle pictures on sheets of paper. Each picture is a rectangle of “pixels”: every cell either has a freckle or it has no freckle. They are jokingly proposing that when they grow up, marry, and have a child, her freckle picture is produced as a result of the following procedure: Kevin’s and Kimberly’s pictures are moved by a parallel translation, and then in each cell a child has a freckle if and only if exactly one of the parents has a freckle in this position. Now they wonder, whether there is a parallel translation that gives their child a specific freckle picture (for example, a lightning), and what is this parallel translation. Input The first line contains two integers, h1 and w1 (1 ≤ h1, w1 ≤ 1000) — the height and the width of Kevin’s freckle picture. Each of the next h1 lines consists of w1 characters ‘*’ and ‘.’. Character ‘*’ means that there is a freckle, and ‘.’ that there is not. The next lines contain Kimberly’s picture in the same format. Its height and width h2 and w2 follow the same constraints. It is guaranteed that Kevin and Kimberly have at least one freckle each. The next lines contain the picture they want for their child in the same format. Its dimensions h3 and w3 also have the same constraints. Output In the first line output “YES” if the desired picture can be produced, and “NO” otherwise. If the answer is positive, then in the second line output two integers, x and y, with the following meaning: if you overlay the pictures so that their upper left corners coincide, then move Kimberly’s picture x cells right (negative number means moving picture left) and y cells down (negative number means moving picture up), and then apply the procedure described above, the resulting picture can be moved by a parallel translation to coincide with the third picture from the input file. Example kids.in 3 3 ..* .*. *.* 3 3 **. ..* .*. 5 2 .* *. ** .* *. kids.out YES 0 2
在很多翻转类型的构造中,常常需要关注其中的标志量:最左/最上之类的元素
原因是,这些元素必须被翻转;而如果不在当前位置将其翻转,那么在之后的翻转中无法将其翻转
在这题中,给出$3$个01矩阵$A,B,C$,需要通过移动,使得他们有$Aoplus Boplus C=0$(零矩阵)
不妨考虑每个矩阵中最左上方的1($x,y$哪个坐标优先无所谓)
有这样的一个性质:如果移动后的$Aoplus Boplus C=0$,那么移动后的$A,B,C$中至少有两个矩阵中 最左上方的1 位置重合
这是因为,如果位置互相不重合,那么最终一定会有至少一个最左上的1不能被翻转成0
于是枚举哪两个矩形的最左上方1重合,然后将合并后的矩形与剩下的一个左上方对齐判断是否能完全翻转即可
需要特判$C=0$的情况
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=3005; char getch() { char ch=getchar(); while(ch!='.' && ch!='*') ch=getchar(); return ch; } void memset(char (*a)[N]) { for(int i=0;i<N;i++) for(int j=0;j<N;j++) a[i][j]='.'; } bool empty(char (*a)[N]) { for(int i=0;i<N;i++) for(int j=0;j<N;j++) if(a[i][j]=='*') return false; return true; } void rev(char &ch) { ch=('.'+'*'-ch); } int px,py; void find(char (*a)[N]) { px=py=-1; for(int i=0;i<N;i++) for(int j=0;j<N;j++) if(a[i][j]=='*') if(px<0 || i<px || (i==px && j<py)) px=i,py=j; } int h[3],w[3]; char a[4][N][N]; int x[3],y[3]; int dx[3],dy[3]; char map[N][N]; int main() { freopen("kids.in","r",stdin); freopen("kids.out","w",stdout); for(int i=0;i<3;i++) { scanf("%d%d",&h[i],&w[i]); memset(a[i]); for(int j=0;j<h[i];j++) for(int k=0;k<w[i];k++) a[i][j][k]=getch(); find(a[i]); x[i]=px,y[i]=py; } for(int i=0;i<2;i++) for(int j=i+1;j<3;j++) { if(x[j]<0) continue; int xpos=max(x[i],x[j]),ypos=max(y[i],y[j]),rem=3-i-j; dx[i]=xpos-x[i],dy[i]=ypos-y[i]; dx[j]=xpos-x[j],dy[j]=ypos-y[j]; memset(a[3]); for(int k=0;k<h[i];k++) for(int l=0;l<w[i];l++) if(a[i][k][l]=='*') rev(a[3][k+dx[i]][l+dy[i]]); for(int k=0;k<h[j];k++) for(int l=0;l<w[j];l++) if(a[j][k][l]=='*') rev(a[3][k+dx[j]][l+dy[j]]); if(empty(a[3])) { if(rem==2 && empty(a[2])) { printf("YES %d %d ",dy[1]-dy[0],dx[1]-dx[0]); return 0; } continue; } if(empty(a[rem])) continue; find(a[3]); xpos=max(px,x[rem]),ypos=max(py,y[rem]); int dpx=xpos-px,dpy=ypos-py; dx[rem]=xpos-x[rem],dy[rem]=ypos-y[rem]; dx[i]+=dpx,dy[i]+=dpy; dx[j]+=dpx,dy[j]+=dpy; memset(map); for(int k=0;k<h[i]+h[j];k++) for(int l=0;l<w[i]+w[j];l++) if(a[3][k][l]=='*') rev(map[k+dpx][l+dpy]); for(int k=0;k<h[rem];k++) for(int l=0;l<w[rem];l++) if(a[rem][k][l]=='*') rev(map[k+dx[rem]][l+dy[rem]]); if(empty(map)) { printf("YES %d %d ",dy[1]-dy[0],dx[1]-dx[0]); return 0; } } printf("NO "); return 0; }
($Beautiful Tables$,$XIX Open Cup: Grand Prix of SPb$) 【medium】
Problem K. Beautiful Tables Input file: standard input Output file: standard output Time limit: 2 seconds Memory limit: 512 mebibytes Alice has a rectangular table consisting of n × m squares. Some squares are empty, and other are filled with integers. Alice thinks that a table is beautiful if: • for every square which has neighbors both left and right, the number in it is half of the sum of numbers in these neighbors, • for every square which has neighbors both up and down, the number in it is half of the sum of numbers in these neighbors. Alice want to check if she can put numbers (not necessary integers) in all empty squares to make her table beautiful. Also, if she can, she is interested if there is an unique way to do it. Input The first line contains two integers n and m (1 ≤ n, m ≤ 10). The next n lines describe of the table. Each of these lines contains m tokens separated by spaces. Each token is either “?” if the respective square is empty, or the respective number if it is filled. All the given numbers are integers not greater than 100 by absolute value. However, there are no such constraints on the numbers which Alice can put in empty cells. Output If there is no way to make the table beautiful, print the only word “None”. If there is an unique way to make the table beautiful, print the word “Unique” on the first line, and then n lines containing the table after filling all empty squares. If there is more than one way to make the table beautiful, print the word “Multiple” on the first line, and then two different solutions: n lines containing one example of the table, then a line with the word “and”, and then n more lines containing a different example of the table. Two tables are considered different if there is at least one square in which they differ. The numbers in tables should be printed as rational fractions with numerator no more than 1018 by absolute value and positive denominator no more than 1018, separated by a single character “/”. Numerator and denominator should be coprime, and a denominator equal to one can be omitted, but only together with the character “/”. Please refer to the examples for more details. Examples standard input 1 3 5 1 2 3 ? ? ? 5 ? ? ? ? ? ? 0 ? standard output 1 Unique 1/1 2/1 3/1 4/1 5/1 13/2 5/1 7/2 2/1 1/2 12/1 8/1 4/1 0/1 -4/1 standard input 2 3 3 1 2 3 7 ? 4 ? 6 5 standard output 2 None standard input 3 2 2 1 2 ? 4 standard output 3 Multiple 1/1 2/1 3/1 4/1 and 1/1 2/1 2/1 4/1
在现场rls喂了个结论,就是如果一行/列有两个已知数,那么这一行/列就可以全部确定
如果再推广一下就能出结论了:每行/列都是等差数列
这有个结论的作用是,如果我们已知一个$2 imes 2$矩形内的数字,就可以推出全部的数字,是一种以小见大的思想
那么我们不妨以左上角的$2 imes 2$矩形为例:设$a[1][1]=a,a[1][2]=a+d_1,a[2][1]=a+d_2,a[2][2]=a+d_1+d_2+d_3$
显然可以将前两列向下推:
[egin{pmatrix} a & a+d_1 & cdots\ a+d_2 & a+d_1+d_2+d_3 & cdots \ vdots & vdots & ddots\ a+(i-1)d_2 & a+d_1+(i-1)(d_2+d_3)end{pmatrix}]
然后我们再利用$a[i][1],a[i][2]$,推出:
[egin{align*} a[i][j]&=a_1+(i-1)d_2+(j-1)[d_1+(i-1)d_3]\ &=a_1+(i-1)d_2+(j-1)d_1+(i-1)(j-1)d_3end{align*}]
于是可以将矩阵中已知的数字拎出来列方程,用高斯消元解一下就好了;注意处理自由元
最后需要特判$n=1$或$m=1$的情况
#include <cstdio> #include <sstream> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; struct frac { ll x,y; //认为x可为负 y必为正 void reduce() { if(!y) return; ll gcd=__gcd(x,y),op=gcd>0?1LL:-1LL; x=x/gcd*op,y=y/gcd*op; } //用于标记时为0,0 否则更建议用0,1 frac(int a=0LL,int b=0LL) { x=a,y=b; reduce(); } frac rev() { if(!x) return frac(0,0); ll op=x>0?1LL:-1LL; return frac(y*op,x*op); } void print() { cout<<x<<'/'<<y; } }; inline frac operator +(frac X,frac Y) { ll lcm=X.y/__gcd(X.y,Y.y)*Y.y; ll val=lcm/X.y*X.x+lcm/Y.y*Y.x; return frac(val,lcm); } inline frac operator -(frac X,frac Y) { Y.x=-Y.x; return X+Y; } inline frac operator *(frac X,ll Y) { ll gcd=__gcd(Y,X.y); return frac(Y/gcd*X.x,X.y/gcd); } inline frac operator *(frac X,frac Y) { ll gcd=__gcd(abs(X.x),Y.y); X.x/=gcd,Y.y/=gcd; gcd=__gcd(abs(Y.x),X.y); Y.x/=gcd,X.y/=gcd; return frac(X.x*Y.x,X.y*Y.y); } inline frac operator /(frac X,ll Y) { ll gcd=__gcd(abs(X.x),Y); return frac(X.x/gcd,Y/gcd*X.y); } inline frac operator /(frac X,frac Y) { if(!Y.x) return frac(0,0); return X*Y.rev(); } inline frac operator ==(frac X,frac Y) { return (X.x==Y.x && X.y==Y.y); } const int N=15; int n,m; frac a[N][N]; int cnt; frac mat[N*N][N]; bool fr[N],valid=true; void gauss() { cnt=0; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(a[i][j].y) { ++cnt; mat[cnt][1]=frac(1,1); mat[cnt][2]=frac(i-1,1); mat[cnt][3]=frac(j-1,1); mat[cnt][4]=frac((i-1)*(j-1),1); mat[cnt][5]=a[i][j]; } for(int i=1;i<=4;i++) { bool flag=false; for(int j=i;j<=cnt;j++) if(mat[j][i].x) { flag=true; for(int k=1;k<=5;k++) swap(mat[j][k],mat[i][k]); break; } if(!flag) { fr[i]=true; ++cnt; for(int k=1;k<=5;k++) swap(mat[i][k],mat[cnt][k]); continue; } for(int j=i+1;j<=cnt;j++) if(mat[j][i].x) { frac mul=mat[j][i]/mat[i][i]; for(int k=1;k<=5;k++) mat[j][k]=mat[j][k]-mul*mat[i][k]; } } for(int i=5;i<=cnt;i++) if(mat[i][5].x) valid=false; } frac val[N]; void set(frac x) { for(int i=4;i>=1;i--) if(fr[i]) val[i]=x; else { frac tmp=mat[i][5]; for(int j=4;j>i;j--) tmp=tmp-mat[i][j]*val[j]; val[i]=tmp/mat[i][i]; } } void fill() { for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j]=val[1]+val[2]*(i-1)+val[3]*(j-1)+val[4]*(i-1)*(j-1); } void print() { for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j].print(),putchar(j==m?' ':' '); } void multiple() { cout<<"Multiple "; set(frac(0,1)),fill(),print(); cout<<"and "; set(frac(1,1)),fill(),print(); } void unique() { cout<<"Unique "; set(frac(0,1)),fill(),print(); } int main() { cin>>n>>m; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { string s; cin>>s; if(s[0]!='?') { stringstream ss; ss<<s; ss>>a[i][j].x; a[i][j].y=1LL; } } gauss(); if(n==1 && m==1) { if(!a[1][1].y) multiple(); else unique(); return 0; } if(!valid) { cout<<"None "; return 0; } if(n==1 || m==1) { if(fr[n==1?3:2]) multiple(); else unique(); return 0; } if(fr[1] || fr[2] || fr[3] || fr[4]) multiple(); else unique(); return 0; }
($Graph Coloring$,$XX Open Cup: Grand Prix of Moscow$) 【medium】
Problem G. Graph Coloring Input file: standard input Output file: standard output Time limit: 1 second Memory limit: 512 mebibytes You are given a tournament, represented as a complete directed graph (for all pairs i, j of two different vertices, there is exactly one edge among i → j and j → i), with n ≤ 3000 vertices. You need to color its edges into 14 colors. There should be no path i → j → k in this graph such that the colors of edges i → j and j → k are the same. It is guaranteed that this is always possible. Input The first line of input contains one integer n (3 ≤ n ≤ 3000): the number of vertices in the given tournament. Next n 1 lines contain the description of the graph: the i-th line contains a binary string with i characters. If the j-th character in this string is equal to ‘1’, then the graph has an edge from (i+ 1) → j. Otherwise, it has an edge from j → (i + 1). Output The output should contain n 1 lines, where the i-th line contains a string with i characters. The j-th character in this string should be a lowercase Latin letter between ‘a’ and ‘n’. If the graph has an edge from (i+ 1) → j, then this character represents the color of the edge from (i+ 1) → j. Otherwise it represents the color of the edge from j → (i + 1). There should be no path i → j → k in this graph such that the colors of edges i → j and j → k are the same. Examples standard input 1 3 1 11 standard input 1 a ab standard input 2 5 1 10 100 0100 standard input 2 a bc def ghij
竟然是一道论文题
一般限定颜色数量在点/边数的$logn$左右的构造染色方案只有两种做法:一种是基于某种原则进行构造(性质能够保证染色数不超过限制),另一种就是二进制位枚举
这题中显然是和二进制位有关
自己只想到了一种染色数不超过$2logn=24$的方案:对于每条边,将两段点的编号异或后取最高位位置,然后按照起点编号是否大于终点再将颜色区分
这样是正确的,因为对于一个固定的$j$,若有一条入边和一条出边的最高位位置相同,那么$j=0,i=k=1$或者$j=1,i=k=0$,即$i,k$要不都比$j$大,要不都比$j$小,那么可以通过起点/终点编号的大小关系将这两类边对应到不同颜色
不过这样并不满足题目中的条件;将$24$减小到$14$并不能仅对原图中的点编号进行比较
考虑组合数$egin{pmatrix} 14\ 7end{pmatrix}=3432>3000$
那么我们对每个节点分配互不相同的$14$位二进制数,且该二进制数中恰有$7$位为$1$
可以这样理解这个二进制数:为$0$的位置表示,该点的入边仅包含这些颜色;为$1$的位置表示,该点的出边仅包含这些颜色
那么对于任意边的两端点对应的二进制数,由于它们互不相同,故必有一些位置起点中为$1$终点中为$0$、或是起点中为$0$终点中为$1$;参照上面的理解,将起点中为$1$、终点中为$0$的任意一种颜色染到这条边上即可
所以,实际上规定二进制数中恰有多少个$1$其实都是可以的,只不过$7$个时可分配的二进制数最多
#include <cstdio> #include <algorithm> using namespace std; const int N=4000; int n; char s[N]; int sz,a[N]; inline int color(int in,int out) { for(int i=0;i<14;i++) if((in>>i)%2==1 && (out>>i)%2==0) return i; } int main() { for(int i=0;i<(1<<14);i++) if(__builtin_popcount(i)==7) a[++sz]=i; scanf("%d",&n); for(int i=1;i<n;i++) { scanf("%s",s+1); for(int j=1;j<=i;j++) putchar('a'+(s[j]-'0'?color(a[i+1],a[j]):color(a[j],a[i+1]))); putchar(' '); } return 0; }
OpenTrain ?G(暂时未出)
($XIX Open Cup: Grand Prix of Wroclaw$) 【medium-hard】
Problem G. Choreography Input file: standard input Output file: standard output Time limit: 10 seconds Memory limit: 512 mebibytes To celebrate the sixteenth anniversary of the unification of Vertical Byteland and Horizontal Byteland, a great parade will pass through the streets of the capital. The court choreographer Byteleon has decided to honor this event with a special choreography of the new national dance: Byterek. Byterek is danced by n^2 dancers who are arranged in a square formation of size n × n. It consists of a sequence of vertical and horizontal phases. During the dance dancers freely swap places with each other, on one condition, that for the time of vertical phases swapping is allowed exclusively within dancer’s own column and during horizontal phases – within one’s own row. The choreography will also carry an additional meaning which should please king Byteasar. Every dancer will have an assigned costume of a specific color, so that the formation creates an image seen from the royal balcony. Byteleon wants the image to initially look like the flag of Vertical Byteland, and at the end of the dance – the flag of Horizontal Byteland. Unfortunately this task seems to be too hard for him, especially that the dance should consist of as few phases as possible, not to bore Byteasar. Please, help Byteleon and write a program that generates phases of Byterek. Input In the first line one integer Z ≤ 100 is given, denoting number of testcases described in following lines. The first line of each test case contains one integer n, denoting the length of columns and rows of the formation. The next n lines, each containing n integers, describe the initial arrangement of the dancers. Every number in [1, n^2] occurs only once in this description and represents the desired position of the dancer in the final arrangement. This means that the final arrangement is a table in which every row and column is sorted, just like in the sample tests. n ∈ [1, 500], sum of n over all test cases does not exceed 1000. Output For each test case, in the first line your program should output an integer k – the minimum number of phases of Byterek. Then it should output k descriptions of arrangements in subsequent phases. The description of one arrangement consists of n rows each consisting of n integers, where each integer in [1, n^2] occurs exactly once. If k > 0, the first arrangement must be possible to reach from the one given in the input after one phase of Byterek. The next one should be possible to reach from the previous one etc. The last arrangement should be equal to a sorted table. The order of vertical and horizontal phases is arbitrary. Example standard input 32 2 3 4 1 3 9 2 7 8 1 4 6 5 3 2 1 2 3 4 standard output 2 2 1 4 3 1 2 3 4 3 2 7 9 8 1 4 5 6 3 2 1 3 5 6 4 8 7 9 1 2 3 4 5 6 7 8 9 0
首先根据output可以感觉出步数并不会很多,但是并不能一眼看出做法;于是考虑由易到难进行充要反推
当步数为$0$的时候:所有元素有序排列
当步数为$1$的时候:每个行/列中都有该行/列中的全部数字,但是不一定有序
当步数为$2$的时候:每个列/行中的元素最终都属于不同的行/列;这样一来,一步操作后每个元素都能进入对应的行/列
这其实还是充要条件
以第一步为纵向、第二步为横向为例;在第一步中,我们必须将所有的元素放到对应的行中,因为第二步没有办法改变元素的行;此时,若一列中出现两个元素属于同一行,那么一步纵向操作后仅能将其中一个放入对应的行,则不能在两步内完成
当步数为$3$的时候:我们总能通过一步操作将任何状态转换为所需步数为$2$的状态,并且第一步是纵向还是横向都无所谓;不妨让第一步是横向移动
于是现在的问题变成,我们如何通过一步横向移动,使得每一列中元素对应的行互不相同
我们可以从左到右让每一列依次满足条件:
对于第$i$列,由于之前$i-1$列已经安排完毕,故属于每一行的元素各剩余$n-i+1$个
我们将第$i$列中的$n$个位置$P_j$和$n$行$R_k$拿出来,共得到$2n$个点
源点向$R_k$均连容量为$1$的边(表示第$k$行只能选$1$个元素);若第$k$行中剩余的元素有属于第$j$行的,就将$R_k$与$P_j$连一条容量为$1$的边(表示可以在第$k$行中进行调整,使得在第$i$列中能够选择一个属于第$j$行的元素);$P_j$与汇点均连容量为$1$的边(表示第$i$列中元素对应的行各不相同);于是共得到$n^2$条边
根据Hall定理,对于如上所述的构图,一定存在完美匹配,且跑Dinic十分高效;可以参考:kimoyami - 二分图通关全攻略
于是我们对于$n$列依次进行匹配,每次的复杂度为$O(ncdot sqrt{n^2})=O(n^2)$,故总复杂度为$O(n^3)$
(暂时不能提交,代码就先咕了)
(待续)