CF1153E Serval and Snake 题解
思路
很明显,对于一个矩阵,如果对其询问的结果是奇数,那么矩阵中一定有一个头或者尾。感性理解一下,如果满足上述条件,说明进去了没出来,或者出来了没进去,就是有一个头或者尾。
那么询问每一行、每一列,如果找到在行上找到两个不同的行结果是奇数,就对这两行二分。列是同理的。
这样询问次数被卡满就是 \(2\times 1000+2\times \lceil \log_2 n\rceil=2020\) 的,刚好超了一次。
发现在询问完 \(n\) 行和 \(n-1\) 列后如果还没找到,那么最后一列一定是合法的,可以省一次。
这样就能 AC 了。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3+5;
int n,cnt;
signed main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
scanf("%d",&n);
int p1 = -1,p2 = -1;
for(int i = 1;i<=n;i++)
{
printf("? %d 1 %d %d\n",i,i,n);
fflush(stdout);
int x;
scanf("%d",&x);
if(x&1)
{
if(p1==-1) p1 = i;
else
{
p2 = i;
break;
}
}
}
if(p2!=-1)
{
int ans1,ans2,l = 1,r = n;
while(l<r)
{
int mid = (l+r)/2;
printf("? %d %d %d %d\n",p1,l,p1,mid);
fflush(stdout);
int x;
scanf("%d",&x);
if(x&1) r = mid;
else l = mid+1;
}
ans1 = l;
l = 1,r = n;
while(l<r)
{
int mid = (l+r)/2;
printf("? %d %d %d %d\n",p2,l,p2,mid);
fflush(stdout);
int x;
scanf("%d",&x);
if(x&1) r = mid;
else l = mid+1;
}
ans2 = l;
printf("! %d %d %d %d\n",p1,ans1,p2,ans2);
fflush(stdout);
return 0;
}
p1 = -1,p2 = -1;
for(int i = 1;i<=n;i++)
{
if(p2==-1&&i==n)
{
p2 = n;
break;
}
printf("? 1 %d %d %d\n",i,n,i);
fflush(stdout);
int x;
scanf("%d",&x);
if(x&1)
{
if(p1==-1) p1 = i;
else
{
p2 = i;
break;
}
}
}
if(p2!=-1)
{
int ans1,ans2,l = 1,r = n;
while(l<r)
{
int mid = (l+r)/2;
printf("? %d %d %d %d\n",l,p1,mid,p1);
fflush(stdout);
int x;
scanf("%d",&x);
if(x&1) r = mid;
else l = mid+1;
}
ans1 = l;
l = 1,r = n;
while(l<r)
{
int mid = (l+r)/2;
printf("? %d %d %d %d\n",l,p2,mid,p2);
fflush(stdout);
int x;
scanf("%d",&x);
if(x&1) r = mid;
else l = mid+1;
}
ans2 = l;
printf("! %d %d %d %d\n",ans1,p1,ans2,p2);
fflush(stdout);
}
return 0;
}

浙公网安备 33010602011771号