题解 [ABC375C] Spiral Rotation

· · 题解

近 40 场以来最难的 C,有点难写。

题意

有一个 N \times N 的网格,每个网格由黑色 # 和白色 . 组成。

按照顺序 i = 1, 2, \ldots, \frac{N}{2} 依次以下进行操作:

最后找出每个单元格的颜色。

分析

这个操作感觉没有说人话,经过一定的模拟发现,每一次操作即把一个左上顶点为 (i,i),右下顶点为 (N-i+1,N-i+1) 的正方形顺时针旋转 90 度。

直接暴力的对于每个 i 旋转是不可取的,需要考虑更好的方法。

设第 i 层表示的单元格集合为 \{ (x,y) \mid x = i \lor x = N-i+1 \lor y = i \lor y = N-i+1\}

因为外层的影响,第 i 层将会被旋转 i 次,但是因为 4 次就会被转回原位,所以就只需要转 i \bmod 4 次即可。

时间复杂度 O(n^2),具体实现有点复杂所以请看代码。

代码

//the code is from chenjh
#include<cstdio>
using namespace std;
int n;
char s[3005][3005],b[3005][3005];
void r(const int i){
    //对第 i 层进行右旋。
    for(int j=i;j<=n-i;j++) b[j][n-i+1]=s[i][j];
    for(int j=i;j<=n-i;j++) b[n-i+1][n-j+1]=s[j][n-i+1];
    for(int j=n-i+1;j>i;j--) b[j][i]=s[n-i+1][j];
    for(int j=n-i+1;j>i;j--) b[i][n-j+1]=s[j][i];
    //将临时存储的数组复制回原数组。
    for(int j=i;j<=n-i;j++) s[i][j]=b[i][j];
    for(int j=i;j<=n-i;j++) s[j][n-i+1]=b[j][n-i+1];
    for(int j=n-i+1;j>i;j--) s[n-i+1][j]=b[n-i+1][j];
    for(int j=n-i+1;j>i;j--) s[j][i]=b[j][i];
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
    for(int i=1;i<=(n>>1);i++)for(int _=i&3;_--;)r(i);//i&3 和 i%4 等价。
    for(int i=1;i<=n;i++) puts(s[i]+1);
    return 0;
}