测试地址:梦幻折纸
做法: 本题需要用到思维。
考虑最后折出来的正方形,从上到下的各层中,有可能有两层在前后侧相连,也有可能有两层在左右侧相连。易知,无论怎么折前后侧的相连都不会成为左右侧,这启发我们分开判断两维是不是成立。
要判断某一维是不是成立,需要观察出下面两个结论:
1.如果两列
i
,
j
i,j
i,j相邻,最后所有
a
(
x
,
i
)
a(x,i)
a(x,i)和
a
(
x
,
j
)
a(x,j)
a(x,j)相连的侧向是相同的。
2.如果三列
i
,
j
,
k
i,j,k
i,j,k中,
i
,
j
i,j
i,j相邻,
j
,
k
j,k
j,k相邻,那么最后
a
(
x
,
i
)
a(x,i)
a(x,i)和
a
(
x
,
j
)
a(x,j)
a(x,j)相连的侧向,与
a
(
x
,
j
)
a(x,j)
a(x,j)和
a
(
x
,
k
)
a(x,k)
a(x,k)相连的侧向是相反的。
有了这个结论,我们就能知道这一维度上的元素之间的相连侧向,然后我们用个栈来判断它是不是合法的就行了,把上面结论中的行列交换也是一样的,于是我们就解决了这一题。
以下是本人代码:
#include <bits/stdc++.h>
using namespace std;
int T,n,m,a[110][110],tot;
int con[10010][2],st[10010][2],top[2];
bool check()
{
top[0]=top[1]=0;
for(int i=1;i<=n*m;i++)
{
if (con[i][0]<0&&st[top[0]][0]!=-con[i][0])
return 0;
if (con[i][0]<0) top[0]--;
if (con[i][0]>0) st[++top[0]][0]=con[i][0];
if (con[i][1]<0&&st[top[1]][1]!=-con[i][1])
return 0;
if (con[i][1]<0) top[1]--;
if (con[i][1]>0) st[++top[1]][1]=con[i][1];
}
return 1;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]);
tot=0;
memset(con,0,sizeof(con));
for(int i=1;i<n;i++)
for(int j=1;j<=m;j++)
{
tot++;
int x=min(a[i][j],a[i+1][j]),y=max(a[i][j],a[i+1][j]);
con[x][i&1]=tot;
con[y][i&1]=-tot;
}
if (!check()) {printf("Cheat\n");continue;}
tot=0;
memset(con,0,sizeof(con));
for(int j=1;j<m;j++)
for(int i=1;i<=n;i++)
{
tot++;
int x=min(a[i][j],a[i][j+1]),y=max(a[i][j],a[i][j+1]);
con[x][j&1]=tot;
con[y][j&1]=-tot;
}
if (!check()) {printf("Cheat\n");continue;}
printf("AllRight\n");
}
return 0;
}