(AtCoder Beginner Contest 375)C - Spiral Rotation
题目大意
给定二维数组
a
[
n
]
[
n
]
,
n
m
o
d
2
=
0
a[n][n],n \mod 2=0
a[n][n],nmod2=0
执行
i
=
1
,
2
,
.
.
.
i=1,2,...
i=1,2,...
n
/
2
n/2
n/2 操作 每次操作对于
∀
x
,
y
∈
[
i
,
n
+
1
−
i
]
\forall x,y\in[i,n+1-i]
∀x,y∈[i,n+1−i]
将
a
[
y
]
[
n
+
1
−
x
]
a[y][n+1-x]
a[y][n+1−x]替换为
a
[
x
]
[
y
]
a[x][y]
a[x][y]
输出
n
2
\frac{n}{2}
2n次操作之后的数组
思路
首先如果按照题目给的方式直接进行模拟,时间复杂度
O
(
n
3
)
O(n^3)
O(n3) 必然是
T
L
E
TLE
TLE
我们考虑找找规律,注意到每次变换操作改变两个量本身和
i
i
i 没有任何关系
我们于是发现一个很有意思的周期
(
x
,
y
)
−
>
(
y
,
n
+
1
−
x
)
−
>
(
n
+
1
−
x
,
n
+
1
−
y
)
−
>
(
n
+
1
−
y
,
x
)
−
>
(
x
,
y
)
(x,y)->(y,n+1-x)->(n+1-x,n+1-y)->(n+1-y,x)->(x,y)
(x,y)−>(y,n+1−x)−>(n+1−x,n+1−y)−>(n+1−y,x)−>(x,y)
然后我们就可以考虑掉消去
i
i
i 对操作次数的影响了
那么如何记录每个点被操作了多少次了呢
不难证明操作数其实是这个
m
i
n
(
x
,
y
,
n
+
1
−
x
,
n
+
1
−
y
)
min(x,y,n+1-x,n+1-y)
min(x,y,n+1−x,n+1−y)
然后我们就可以不枚举
i
i
i 了,实现
O
(
n
2
)
O(n^2)
O(n2) 的解法
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#define rep(i,x,y) for(ll i=x;i<=y;++i)
#define per(i,x,y) for(ll i=x;i>=y;--i)
using namespace std;
typedef long long ll;
const ll V=3010;
ll n,b[V][V];
char a[V][V],c[V][V];
inline ll in()
{
ll res=0,f=1;
char ch;
while((ch=getchar())<'0'||ch>'9')
if(ch=='-') f=-1;
res=res*10+ch-'0';
while((ch=getchar())>='0'&&ch<='9')
res=res*10+ch-'0';
return res*f;
}
inline void put(ll x)
{
if(x<0) putchar('-'),x*=-1;
if(x>9) put(x/10);
putchar(x%10+48);
}
int main()
{
n=in();
rep(i,1,n)
{
rep(j,1,n)
{
a[i][j]=getchar(),c[i][j]=a[i][j];
ll x=n-i+1,y=n-j+1;
b[i][j]=min(i,min(j,min(x,y)));
b[i][j]%=4;
}
getchar();
}
rep(i,1,n)
rep(j,1,n)
{
if(b[i][j]==1) c[j][n-i+1]=a[i][j];
else if(b[i][j]==2) c[n+1-i][n+1-j]=a[i][j];
else if(b[i][j]==3) c[n+1-j][i]=a[i][j];
else c[i][j]=a[i][j];
}
rep(i,1,n)
{
rep(j,1,n)
putchar(c[i][j]);
putchar(10);
}
return 0;
}