题目
aslky
有一个 n×n 的矩形,每个位置上都有一个数,有 q 次操作,每次他会让你上下翻转 (UD),左右反转 (LR),顺时针旋转 90∘(SZ),逆时针旋转 90∘(NZ),请你输出最后的矩形。
输入格式
第一行,两个数 n,q。
接下来 n 行,每行 n个数,代表矩形。
接下来 q 行,每行一个字符串,代表操作。
输出格式
n 行,每行 n 个数代表矩形。
数据规模与约定
对于 10% 的数据,1≤n≤10;
对于 100% 的数据,1≤n≤1000,1≤q≤1e6
Sample Input
3 3 1 2 3 1 2 3 1 2 3 NZ SZ SZ
Sample Output
1 1 1 2 2 2 3 3 3
题解
一次操作的复杂度为O(N^2),直接模拟复杂度为O(q*N^2),n<=1000,q<=1e6,计算次数为1e12,直接模拟必定超时,需要优化。如果该题无翻转变换只有旋转变化就简单了,SZ和NZ可以相互抵消,最后再对结果模4,就能大程度的优化操作次数。但加上翻转变化,那就要考虑两种翻转变化的优化,以及翻转变化和旋转变化的相互影响,还有图像在这几种变化中拥有多少种状态。
通过画图模拟,我们可以得出,图像在这2种变化中共有8种状态,首先是,原图像只通过旋转可以有4种状态,加上翻转变化后,我们发现无论是上下翻转还是左右翻转,其实都是把图像变成镜像面,图像在这种镜像面同样有4种形态,合起来共8种。
对翻转变化的优化,我们容易发现,同时经过两次上下翻转或者左右翻转后图像复原,所以,单向翻转变化可以模2.再对翻转变化进行研究,发现图像经过一次上下翻转一次左右翻转,会脱离镜像图变为原图。归纳:一个图像经过一次翻转变化后变为镜像图,这个镜像图再经过一次翻转变换后复原为原图。
接下来是研究两种变化之间的关系。容易发现上下翻转的图像通过旋转可变为左右翻转的图像,通过这个性质我们可以得出一个等式:LR=UD+2*SZ. 通过这个等式我们可以把所有的左右翻转变化变为上下翻转变化加上旋转变化。
剩下的就是考虑在翻转变化后旋转变化有何影响,容易知道,在镜像图状态时,对图像的顺时针旋转将相当于原图像的逆时针旋转,逆时针亦然。
暴力模板
#include<iostream> #include<algorithm> using namespace std; int s[1005][1005]; int f[1005][1005]; int n; void UD() { for (int i = 0; i < n / 2; i++) { for (int j = 0; j < n; j++) { swap(s[i][j], s[n - i - 1][j]); } } } void LR() { for (int i = 0; i < n / 2; i++) { for (int j = 0; j < n; j++) { swap(s[j][i], s[j][n - i - 1]); } } } void SZ() { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { f[j][n - i - 1] = s[i][j]; } } for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { s[i][j] = f[i][j]; } } } void NZ() { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { f[n - 1 - j][i] = s[i][j]; } } for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { s[i][j] = f[i][j]; } } } void pr() { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) cout << s[i][j] << ' '; cout << ' '; } } int main() { ios::sync_with_stdio(0); int q; char com[5]; cin >> n >> q; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) cin >> s[i][j]; while (q--) { cin >> com; switch (com[0]) { case 'U': UD(); break; case 'L': LR(); break; case 'S': SZ(); break; case 'N': NZ(); break; } /*pr(); cout << ' ';*/ } pr(); }
数据生成
#include<iostream> #include<time.h> #include<algorithm> #include<map> using namespace std; int r(int l, int r) { return rand() % (r+1 - l) + l; } char s[][3] = { "UD","LR","SZ","NZ" }; int main() { ios::sync_with_stdio(0); srand(time(0)); int n=2, q=r(1,10); int k = 1; cout << n << ' ' << q << ' '; cout << "1 2 "; cout << "4 3 "; while (q--) { cout << s[r(0, 3)] << ' '; } return 0; }
AC代码
#include<iostream> #include<algorithm> using namespace std; int s[1005][1005]; int f[1005][1005]; int n; void UD() { for (int i = 0; i < n/2; i++) { for (int j = 0; j < n; j++) { swap(s[i][j], s[n - i-1][j]); } } } void SZ() { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { f[j][n - i-1] = s[i][j]; } } for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { s[i][j] = f[i][j]; } } } void pr() { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) cout << s[i][j] << ' '; cout << ' '; } } int main() { ios::sync_with_stdio(0); int q; char com[5]; cin >> n >> q; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) cin >> s[i][j]; int flag = 1; int sz = 0; while (q--) { cin >> com; switch (com[0]){ case 'U': if (flag == 1) { sz++; flag *= -1; } else { sz--; flag *= -1; } break; case 'L': if (flag == 1) { sz--; flag *= -1; } else { sz++; flag *= -1; } break; case 'S': if (flag == 1) { sz++; } else { sz--; } break; case 'N': if (flag == 1) { sz--; } else { sz++; } break; } if(sz>=0) sz %= 4; else { sz %= 4; sz += 4; } } if (flag==1) { while (sz--)SZ(); } else { sz--; sz += 4; sz %= 4; while (sz--)SZ(); UD(); } pr(); }