ARC070F HonestOrUnkind 题解

题目链接:ARC070F - HonestOrUnkind

有点厉害的 Ad-hoc

首先如果坏人数量大于等于好人就是分辨不了的,因为其中好人个数个坏人可以互相说是好人,然后说好人是坏人,此时好人的特征和坏人一样了。

首先如果我们能找到一个好人,则只需要 $ n $ 次询问就可以获得所有人的身份。

考虑要尽量缩小好人和坏人的集合。我们考虑维护一个 疑似好人 的集合,每次选择一个未加入的人,然后选择上一个加入的疑似好人出来问即将要加入的人的身份。枚举四种情况。

  1. 如果疑似好人是好人,回答的是 $ \texttt{Y} $,则新要加入的人是好人。
  2. 如果疑似好人是好人,回答的是 $ \texttt{N} $,则新要加入的人是坏人。
  3. 如果疑似好人是坏人,回答的是 $ \texttt{Y} $,则新要加入的人可能是好人也可能是坏人
  4. 如果疑似好人是坏人,回答的是 $ \texttt{N} $,则新要加入的人可能是好人也可能是坏人。

我们发现如果回答是 $ \texttt{N} $,则当前被拉出来的疑似好人和即将加入的人至少存在一个好人,而好人比坏人多,所以可以直接丢掉这两个人。而当一个好人进入后,只会有好人再进入。因为好人的数量始终大于坏人,所以最后一个加入的一定是好人,此时用了 $ n $ 次询问,再用 $ n $ 次询问判断每个人的身份即可。

代码:

#include<bits/stdc++.h>
#define time(null) chrono::steady_clock::now().time_since_epoch().count()
#define int long long
#define uint unsigned long long
#define debug() cout<<"come here\n"
#define INF 0x3f3f3f3f3f3f3f3f
#define pii pair<int,int>
#define pb push_back
#define Code return
#define by 0
#define MCYYDS ;
using namespace std;
int qpow(int a,int b,int p=INF){int ret=1;while(b){if(b&1)ret=(ret*a)%p;a=(a*a)%p;b>>=1;}return ret;}
inline int read(){int ret=0,f=1;char ch=getchar();while(ch<'0'||ch>'9')f=(ch=='-'?-1:f),ch=getchar();while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+(ch^48),ch=getchar();return ret*f;}
inline void write(int x){if(x<0){putchar('-');write(-x);return ;}if(x>9)write(x/10);putchar((char)(x%10+48));}
inline void writech(int x,char ch){write(x);putchar(ch);}
stack<int> stk;
signed main()
{
//	ios::sync_with_stdio(0);
//	cin.tie(0);
//	cout.tie(0);
	int a,b;
	cin>>a>>b;
	if(a<=b)cout<<"Impossible"<<endl;
	else
	{
		stk.push(0);
		vector<int> ans(a+b,0);
		for(int i=1;i<a+b+a+b;i++)
		{
			if(stk.empty())
			{
				stk.push(i);
				continue;
			}
			cout<<"? "<<stk.top()<<' '<<i%(a+b)<<endl;
			char c;
			cin>>c;
			if(c=='Y'&&i<a+b)stk.push(i%(a+b));
			else if(c=='Y')ans[i%(a+b)]=1;
			else if(i<a+b)stk.pop();
		}
		cout<<"! ";
		for(auto x:ans)
		{
			cout<<x;
		}
		cout<<endl;
	}
	Code by MCYYDS
}

posted @ 2026-09-29 21:23  MCYYDS  阅读(5)  评论(0)    收藏  举报