思路
每次所有滑块滑向上左下右四个方向。
考虑操作的规律。相对的方向做多次只用保留最后一次。同一种操作两两之间如果没有反向的操作,则后面一次无用。用栈来删,发现最后去掉开头结尾 次操作后,四种操作以一个合法的顺序重复多次,形如多次转圈。
开头处理若干步后所有的滑块都在某个角落。此时转一圈只改变每个滑块的位置,不改变整体的形状,是一个置换。
做一轮就可以知道原来在一个位置的滑块会去到的新位置。求出置换后,要把他做 次,可以快速幂。也可以找出置换环后 。复杂度 。
code
int n,m,q,a[maxn];
char s[maxq];
int id[maxn],to[maxn],tmp[maxn],res[maxn];
int b[maxm][maxm];
int st[maxn],tp;
bool vis[maxn];
void trans(int op){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)b[i][j]=id[(i-1)*m+j];
}
if(op==0){
for(int j=1;j<=m;j++){
vector<int> id1,id2;
for(int i=1;i<=n;i++){
if(a[b[i][j]])id1.pb(b[i][j]);
else id2.pb(b[i][j]);
}
for(int i=0;i<id1.size();i++)b[i+1][j]=id1[i];
for(int i=0;i<id2.size();i++)b[i+1+id1.size()][j]=id2[i];
}
}
if(op==1){
}
if(op==2){
}
if(op==3){
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)id[(i-1)*m+j]=b[i][j];
}
}
void work(){
n=read();m=read();
for(int i=1;i<=n;i++){
scanf("%s",s+1);
for(int j=1;j<=m;j++)a[(i-1)*m+j]=(s[j]=='.'?0:s[j]-'A');
}
for(int i=1;i<=n*m;i++)id[i]=i;
q=read();scanf("%s",s+1);
for(int i=1;i<=q;i++){
if(s[i]=='G')st[++tp]=0;
if(s[i]=='D')st[++tp]=1;
if(s[i]=='L')st[++tp]=2;
if(s[i]=='P')st[++tp]=3;
if(tp>1&&(st[tp-1]==st[tp]||(st[tp-1]^1)==st[tp]))st[tp-1]=st[tp],tp--;
if(tp>2&&st[tp]==st[tp-2])tp--;
}
q=tp;
if(q<8){
for(int i=1;i<=q;i++)trans(st[i]);
}
else{
for(int i=1;i<=q%4+4;i++)trans(st[i]);
int lst=(q-(q%4+4))/4;
for(int i=1;i<=n*m;i++)tmp[i]=id[i];
for(int i=(q%4)+5;i<=(q%4)+8;i++)trans(st[i]);
for(int i=1;i<=n*m;i++)to[tmp[i]]=id[i];
for(int i=1;i<=n*m;i++)if(!vis[i]){
vector<int> cyc;
int x=i;
while(!vis[x])vis[x]=1,cyc.pb(x),x=to[x];
for(int j=0;j<cyc.size();j++)res[cyc[j]]=cyc[(j+lst)%cyc.size()];
}
for(int i=1;i<=n*m;i++)id[i]=res[tmp[i]];
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(!a[id[(i-1)*m+j]])putchar('.');
else putchar(char(a[id[(i-1)*m+j]]+'A'));
}
puts("");
}
}