PDF
分析思路挺简单的,题目中的每个命令(包括命令的逆)相当于一个置换。
用\(O(n^2k)\)的时间复杂度从右往左求出这些置换的乘积A,然后求m使Am = I(I为全等置换)
还是先把A分解循环,m则等于所有循环节长度的最小公倍数。
代码
template<class T>il T read(){
rg T data=0,w=1;rg char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') w=-1;ch=getchar();}
while(isdigit(ch)) data=data*10+ch-'0',ch=getchar();
return data*w;
}
template<class T>il T read(rg T&x) {return x=read<T>();}
typedef long long ll;
using namespace std;
int gcd(int a,int b) {return b?gcd(b,a%b):a;}
int lcm(int a,int b) {return a/gcd(a,b)*b;}
int newpos(int n,int i,int j,co char*op){
if(op[0]=='r') return ID(n-1-j,i); // rot
if(op[0]=='s') return ID(i,n-1-j); // sym
if(op[0]=='b'&&op[1]=='h') // bhsym
return i<n/2?ID(i,j):ID(i,n-1-j);
if(op[0]=='b'&&op[1]=='v') // bvsym
return i<n/2?ID(i,j):ID(n/2+n-i-1,j);
if(op[0]=='d')
return i%2==0?ID(i/2,j):ID(n/2+i/2,j);
if(op[0]=='m'){
int k=i/2;
if(j<n/2)
return i%2==0?ID(2*k,2*j):ID(2*k,2*j+1);
else
return i%2==0?ID(2*k+1,2*(j-n/2)):ID(2*k+1,2*(j-n/2)+1);
}
return assert(op[0]=='i'),ID(i,j);
}
co int N=1024;
int orig[N*N];
void apply(int*image,int n,co char*op){
bool inv=op[strlen(op)-1]=='-';
copy(image,image+n*n,orig);
for(int i=0;i<n;++i)for(int j=0;j<n;++j){
int p=ID(i,j),p2=newpos(n,i,j,op);
if(!inv) image[p2]=orig[p];
else image[p]=orig[p2];
}
}
int vis[N*N];
int solve(int*p,int n){
fill(vis,vis+n,0);
int ans=1;
for(int i=0,j,len;i<n;++i)if(!vis[i]){
j=i,len=0;
do vis[j]=1,j=p[j],++len;
while(j!=i);
ans=lcm(ans,len);
}
return ans;
}
int cur[N*N];
int main(){
// freopen(".in","r",stdin),freopen(".out","w",stdout);
int T,n,n2;
read(T),read(n);
for(;T--;n=n2){
for(int i=0;i<n*n;++i) cur[i]=i;
vector<string> ops;
for(int i=0;;++i){
static char op[10];
if(scanf("%s",op)==EOF) break;
if(isdigit(op[0])) {sscanf(op,"%d",&n2);break;}
ops.push_back(op);
}
for(int i=ops.size()-1;i>=0;--i)
apply(cur,n,ops[i].c_str());
printf("%d\n",solve(cur,n*n));
if(T) puts("");
}
return 0;
}