AT_arc070_d HonestOrUnkind

AT_arc070_d\(\mathbf{} \begin{Bmatrix} \frac{{\Large ARC070D} }{{\color{Red}\Large Solution} }\mathbf{} {No.20} \end{Bmatrix}\times{}\) NeeDna

很巧妙的构造!

题意:

共有 \(n\) 个人,其中有 \(a\) 个诚实的人,\(b\) 个不诚实的人,你可以做出 \(2 \times n\) 次询问。每次询问为 \(query(x,y)\) 含义为向 \(x\) 询问 \(y\) 的身份,你会得到如下结果:

x 诚实 x 不诚实
y 诚实 Y Y/N
y 不诚实 N Y/N

问所有人的诚实与否。

题解:

首先如果 $ a\le b$ 那么一定是 \(Impossible\) 原因是只要其中 \(a\) 个坏人说自己阵营的都是好人,对方阵营的都是坏人,坏人就变得和好人一样了,显然无法分辨。

接下来关注到一个性质,那就是如果 \(query(x,y)=N\) 那么 \(x,y\) 之中一定有一个不诚实的人!又因为此时 \(a>b\),所以我们可以做一个栈,保证坏人在好人底下,那就可以得到如下策略:

query(x,y)={N(代表x,y至少有一个坏人)把栈中的x,y都删掉Y(代表所有人都是坏人或者x,y都是好人)x,y都加入栈

因为 \(a>b\),而且每次删掉的坏人一定比好人多,所以保证栈顶一定是好人。这样就用了 \(n\) 次询问确定了一个好人,还有 \(n\) 次询问只需要用好人询问每一个人即可。

ac code:

#include<bits/stdc++.h>
using namespace std;
const int N=5e4+10;
int a,b,n,vis[N];
stack<int> stk;
char query(int x,int y){char s;cout<<"? "<<x-1<<" "<<y-1<<endl;cin>>s;return s;}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>a>>b;n=a+b;
	if(a<=b){cout<<"Impossible"<<endl;return 0;}
	for(int i=1;i<=n;i++){
		if(stk.empty()) stk.push(i);
		else{
			int t=stk.top();
		    if(query(t,i)=='N') stk.pop();
		    else stk.push(i);
		}
	}
	int tr=stk.top();
	for(int i=1;i<=n;i++){if(query(tr,i)=='Y') vis[i]=1;}
	cout<<"! ";for(int i=1;i<=n;i++) cout<<vis[i];cout<<endl;
	return 0;
}

posted @ 2025-05-31 10:41  NeeDna  阅读(16)  评论(0)    收藏  举报