题解:AT_agc006_e [AGC006E] Rotate 3x3
Solution
这题真的有黑吗?
考虑先找一找必要条件。显然,我们把每一列当做整体,那么每一列的属性有位置
显然每次操作列的位置的奇偶性不变,即必须满足
然后模拟对奇偶位置的排序,得到一个顺序合适但是方向还不满足的组合。
显然上述的排序是必不可少的,和逆序对数相关,可以直接计算。
注意到后续的调整操作,奇数位和偶数位执行的次数都必须是偶数次,否则最后会乱序:那么我们认为操作对中心列的朝向没有影响。
那么发现每次操作,对于旁边列的方向之和的奇偶性不变(朝上是
奇数位置的
由于
UPD:好像还要证明第一列和最后一列的情况,补充第一列即可。
中间一步用到了上面那种方法的结论。
复杂度
#include<bits/stdc++.h>
#define ffor(i,a,b) for(int i=(a);i<=(b);i++)
#define roff(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
const int MAXN=1e5+10;
int n,a[4][MAXN],flp[MAXN],pos[MAXN],pre[MAXN],tr[MAXN];
void update(int pos) {
while(pos<=n) tr[pos]^=1,pos+=pos&-pos;
return ;
}
int query(int pos) {
int ans=0;
while(pos) ans^=tr[pos],pos-=pos&-pos;
return ans;
}
int main() {
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n;
ffor(i,1,3) ffor(j,1,n) cin>>a[i][j];
ffor(i,1,n) {
if(a[2][i]==a[1][i]+1&&a[3][i]==a[2][i]+1) {
if((a[1][i]+2)%3) return cout<<"No",0;
pos[(a[1][i]+2)/3]=i;
}
else if(a[2][i]==a[3][i]+1&&a[1][i]==a[2][i]+1) {
if((a[3][i]+2)%3) return cout<<"No",0;
pos[(a[3][i]+2)/3]=i,flp[(a[3][i]+2)/3]=1;
}
else return cout<<"No",0;
}
ffor(i,1,n) if((pos[i]-i)%2) return cout<<"No",0;
int sum[2]={0,0},psl[2]={0,0};
ffor(i,1,n) sum[i&1]^=flp[i];
ffor(i,1,n) if(i%2==1) psl[0]^=query(n)^query(pos[i]),update(pos[i]);
ffor(i,1,n) tr[i]=0;
ffor(i,1,n) if(i%2==0) psl[1]^=query(n)^query(pos[i]),update(pos[i]);
if(sum[0]!=psl[0]||sum[1]!=psl[1]) return cout<<"No",0;
cout<<"Yes";
return 0;
}