题目大意
给你一个 n × m n\times m n×m的字符矩阵以及 q q q次操作,每次操作给出 a , b a,b a,b两个值,进行如下操作:
- 将左上角为 ( 1 , 1 ) (1,1) (1,1),右下角为 ( a , b ) (a,b) (a,b)的矩阵翻转180度
- 将左上角为 ( 1 , b + 1 ) (1,b+1) (1,b+1),右下角为 ( a , m ) (a,m) (a,m)的矩阵翻转180度
- 将左上角为 ( a + 1 , 1 ) (a+1,1) (a+1,1),右下角为 ( n , b ) (n,b) (n,b)的矩阵翻转180度
- 将左上角为 ( a + 1 , b + 1 ) (a+1,b+1) (a+1,b+1),右下角为 ( n , m ) (n,m) (n,m)的矩阵翻转180度
简单来说就是每次将矩阵分成四个矩阵,每个矩阵分别旋转180度。
输出 n n n次操作后的矩阵。
题解
首先我们可以想到,将一个矩阵翻转180度等同于将这个矩阵的行上下翻转,列左右翻转,这样行和列都独立出来了,我们就可以分别处理,且处理方式相同。
先看行如何处理。令 f i f_i fi表示原来的第 i i i行当前到了第 f i f_i fi行, f i f_i fi的初值为 i i i,那么对于每次操作的 a a a, f i f_i fi有以下变化
- 若 1 ≤ f i ≤ a 1\leq f_i\leq a 1≤fi≤a,则 f i = a − f i + 1 f_i=a-f_i+1 fi=a−fi+1
- 若 a < f i ≤ n a<f_i\leq n a<fi≤n,则 f i = n − f i + a + 1 f_i=n-f_i+a+1 fi=n−fi+a+1
我们发现,下面的式子只比上面的式子多一个 n n n。也就是说,在模 n n n的意义下,无论 f i f_i fi的值为多少,都会变为 a − f i + 1 a-f_i+1 a−fi+1。
那么问题就好解决了。我们分别来看每次操作后 f i f_i fi的值
- 一开始, f i = i f_i=i fi=i
- 第一次, f i = a 1 + 1 − f i = a 1 + 1 − i f_i=a_1+1-f_i=a_1+1-i fi=a1+1−fi=a1+1−i
- 第二次, f i = a 2 + 1 − f i = a 2 + 1 − ( a 1 + 1 − i ) = a 2 − a 1 + i f_i=a_2+1-f_i=a_2+1-(a_1+1-i)=a_2-a_1+i fi=a2+1−fi=a2+1−(a1+1−i)=a2−a1+i
观察发现,当 q q q为偶数时, i i i的系数为 1 1 1;当 q q q为奇数时, i i i的系数为 − 1 -1 −1。对于 f i f_i fi中不包含 i i i项的部分,我们可以在询问时求出,令这个值为 v v v,则
- 当 q q q为偶数时, f i = v + i f_i=v+i fi=v+i
- 当 q q q为奇数时, f i = v − i f_i=v-i fi=v−i
于是我们就得出了 f i f_i fi。
令 g j g_j gj表示原来的第 j j j行列当前到了第 g j g_j gj列,则 g j g_j gj可以用同样的方法求出。
f i f_i fi和 g j g_j gj都求出来了,令原矩阵为 A A A,新矩阵为 B B B,则有 B f i , g j = A i , j B_{f_i,g_j}=A_{i,j} Bfi,gj=Ai,j。这样就可以求出答案了。
时间复杂度为 O ( q + n m ) O(q+nm) O(q+nm)。
code
#include<bits/stdc++.h>
#define lc k<<1
#define rc k<<1|1
using namespace std;
int n,m,q,v1,v2,f,a[2]={1,-1};
char ch,c[500005],ans[500005];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n*m;i++){
ch=getchar();
while(ch<'a'||ch>'z') ch=getchar();
c[i]=ch;
}
scanf("%d",&q);f=q&1;
for(int i=1,x,y;i<=q;i++){
scanf("%d%d",&x,&y);
v1=(x+1-v1+n)%n;v2=(y+1-v2+m)%m;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int k1=(a[f]*i+v1-1+2*n)%n+1,k2=(a[f]*j+v2-1+2*m)%m+1;
ans[m*(k1-1)+k2]=c[m*(i-1)+j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
printf("%c",ans[m*(i-1)+j]);
}
printf("\n");
}
return 0;
}