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;
}
posted @ 2024-04-08 16:33  pyy1  阅读(31)  评论(0)    收藏  举报