题目链接
对于格子 ( i , j ) (i,j) (i,j),若 i + j i+j i+j为奇数则称为奇点,否则称为偶点。
首先发现询问距离为2的两个格子就可以知道它们是否值相同。已知 ( 1 , 1 ) (1,1) (1,1)格子值为1, ( n , n ) (n,n) (n,n)格子值为0,一遍BFS可以求出所有偶点的值。
如果 ( 1 , 2 ) (1,2) (1,2)格子的值已知,那么再一遍BFS可以求出所有奇点的值。我们假设 ( 1 , 2 ) (1,2) (1,2)格子值为0/1,得到两种结果。因题目保证有解,所以两种结果下必然存在一组合法询问的答案不同,我们得到这组询问的答案就知道哪种结果正确了。
我们用DP分别求出两种结果下所有询问的答案即可。设 S [ x 1 ] [ y 1 ] [ x 2 ] [ y 2 ] S[x1][y1][x2][y2] S[x1][y1][x2][y2]表示 ( x 1 , y 1 ) (x1,y1) (x1,y1)与 ( x 2 , y 2 ) (x2,y2) (x2,y2)之间是否有合法回文路径,它为YES的条件是: ( x 1 , y 1 ) (x1,y1) (x1,y1)和 ( x 2 , y 2 ) (x2,y2) (x2,y2)两个格子的值相同,且它们之间存在合法路径,并满足: ( x 1 , y 1 ) (x1,y1) (x1,y1)与 ( x 2 , y 2 ) (x2,y2) (x2,y2)相同或接壤,或者存在 ( x 1 ′ , y 1 ′ ) (x1',y1') (x1′,y1′), ( x 2 ′ , y 2 ′ ) (x2',y2') (x2′,y2′),满足 ( x 1 ′ , y 1 ′ ) (x1',y1') (x1′,y1′)是 ( x 1 , y 1 ) (x1,y1) (x1,y1)路径的后继, ( x 2 ′ , y 2 ′ ) (x2',y2') (x2′,y2′)是 ( x 2 , y 2 ) (x2,y2) (x2,y2)路径的前驱,且 S [ x 1 ′ ] [ y 1 ′ ] [ x 2 ′ ] [ y 2 ′ ] S[x1'][y1'][x2'][y2'] S[x1′][y1′][x2′][y2′]为YES。用记忆化搜索写起来会方便些,复杂度为 O ( n 4 ) O(n^4) O(n4)。
在两遍BFS中一共用到了 n 2 − 3 n^2-3 n2−3个询问,最后用到了一个询问,询问总数为 n 2 − 2 n^2-2 n2−2,符合题意。
#include
#include
#include
#include
#include
#include
#include
#define LL long long
using namespace std;
LL read( )
{
LL sum=0;char c=getchar( );bool f=0;
while(c<'0' || c>'9') {if(c=='-') f=1;c=getchar( );}
while(c>='0' && c<='9') {sum=sum*10+c-'0';c=getchar( );}
if(f) return -sum;
return sum;
}
int n;
const int dx[ ]={2,1,1,0,0,-1,-1,-2};
const int dy[ ]={0,1,-1,2,-2,1,-1,0};
const int DX[ ]={0,1,-1,0};
const int DY[ ]={1,0,0,-1};
#define CI const int
bool CH(int &x1,int &y1,int &x2,int &y2)
{
if(x1<=x2&&y1<=y2) return 1;
swap(x1,x2);swap(y1,y2);
return(x1<=x2&&y1<=y2);
}
bool ASK(CI &x1,CI &y1,CI &x2,CI &y2)
{
printf("? %d %d %d %d\n",x1,y1,x2,y2);
fflush(stdout);return read( )^1;
}
int qx[2505],qy[2505];
struct EX
{
bool S[55][55],vis[55][55];
bool F[55][55][55][55],V[55][55][55][55];
void BFS(bool T)
{
int h,t,i,x,y,x1,y1,x2,y2,rx,ry;
if(!T) {h=1;t=2;qx[1]=1;qy[1]=1;S[1][1]=1;vis[1][1]=1;qx[2]=n;qy[2]=n;S[n][n]=0;vis[n][n]=1;}
else {h=t=1;qx[1]=1;qy[1]=2;S[1][2]=0;vis[1][2]=1;}
while(h<=t)
{
x=qx[h];y=qy[h];h++;
for(i=0;i<8;i++)
{
x1=x;y1=y;x2=x1+dx[i];y2=y1+dy[i];
if(x2<1||x2>n||y2<1||y2>n||vis[x2][y2]) continue;
if(CH(x1,y1,x2,y2))
{
if(x==x2&&y==y2) rx=x1,ry=y1;else rx=x2,ry=y2;
vis[rx][ry]=1,S[rx][ry]=S[x][y]^ASK(x1,y1,x2,y2),qx[++t]=rx,qy[t]=ry;
}
}
}
}
bool DFS(int x1,int y1,int x2,int y2)
{
if(V[x1][y1][x2][y2]) return F[x1][y1][x2][y2];
V[x1][y1][x2][y2]=1;
if(S[x1][y1]!=S[x2][y2]) return F[x1][y1][x2][y2]=0;
if(abs(x1-x2)+abs(y1-y2)<=1) return F[x1][y1][x2][y2]=1;
int i,j,X1,Y1,X2,Y2;
for(i=0;i<2;i++)
{
X1=x1+DX[i];Y1=y1+DY[i];
if(X1<1||X1>n||Y1<1||Y1>n) continue;
for(j=2;j<4;j++)
{
X2=x2+DX[j];Y2=y2+DY[j];
if(X2>=1&&X2<=n&&Y1>=1&&Y2<=n&&CH(X1,Y1,X2,Y2)&&DFS(X1,Y1,X2,Y2)) return F[x1][y1][x2][y2]=1;
}
}
return F[x1][y1][x2][y2]=0;
}
void output( )
{
puts("!");
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++) printf("%d",S[i][j]);
puts("");
}
}
}K1,K2;
int main( )
{
n=read( );
K1.BFS(0);K1.BFS(1);
int i,j,k,t,x1,y1,x2,y2;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
K2.S[i][j]=K1.S[i][j]^((i+j)&1);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
for(k=1;k<=n;k++)
for(t=1;t<=n;t++)
{
x1=i;y1=j;x2=k;y2=t;
if(!CH(x1,y1,x2,y2)) continue;
K1.DFS(x1,y1,x2,y2),K2.DFS(x1,y1,x2,y2);
if(K1.F[x1][y1][x2][y2]==K2.F[x1][y1][x2][y2]) continue;
if(abs(x1-x2)+abs(y1-y2)==1) continue;
if(ASK(x1,y1,x2,y2)==K1.F[x1][y1][x2][y2]) K2.output( );
else K1.output( );
return 0;
}
return 0;
}