ARC153B Grid Rotations

ARC153B Grid Rotations

题目大意

给你一个 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 1fia,则 f i = a − f i + 1 f_i=a-f_i+1 fi=afi+1
  • a < f i ≤ n a<f_i\leq n a<fin,则 f i = n − f i + a + 1 f_i=n-f_i+a+1 fi=nfi+a+1

我们发现,下面的式子只比上面的式子多一个 n n n。也就是说,在模 n n n的意义下,无论 f i f_i fi的值为多少,都会变为 a − f i + 1 a-f_i+1 afi+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+1fi=a1+1i
  • 第二次, 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+1fi=a2+1(a1+1i)=a2a1+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=vi

于是我们就得出了 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;
}
  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值