题解:AT_arc070_d [ARC070F] HonestOrUnkind

Luogu AT

考虑当 \(a\le b\) 的时候,\(a\) 个坏人可以说坏人是好人,这样好人和坏人就无法分辨了,无解。

否则考虑当 \(a>b\) 的时候,我们只要在 \(n\) 次询问内找出一个好人,再用 \(n\) 次询问即可求出所有人的好坏。由于我们只需要一个好人,这启发我们用一个好人换掉一个坏人。这里有一个非常强大的做法,维护一个单调栈状物,栈顶都是好人,栈底都是坏人。每次加入一个人,都向栈顶询问这个人的好坏,则有:

  • 如果回答 Yes,则要么两个人都是好人,要么栈顶是坏人,那么直接入栈即可。
  • 如果回答 No,则要么栈顶是好人,新来的是坏人,要么栈顶是坏人,则这两个人中定然有一个坏人,把两个人都干掉即可。

考虑每干掉一个坏人,最多只用一个好人,所以最后栈顶一定是一个好人,于是就做完了。

参考资料:ARC070F 题解

Code:

#include<iostream>
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define per(i,l,r) for(int i=(l);i>=(r);i--)
using namespace std;
const int maxn=4005;
int st[maxn];
char s[maxn],ans[maxn];
void query(int x,int y){
	printf("? %d %d\n",x-1,y-1);
	fflush(stdout);
	scanf("%s",s);
}
int main(){
	int ia,ib,in;
	cin>>ia>>ib;
	in=ia+ib;
	if(ia<=ib){
		cout<<"Impossible"<<endl;
		return 0;
	}
	int top=0;
	rep(v1,1,in){
		if(!top){
			st[++top]=v1;
			continue;
		}
		query(st[top],v1);
		if(s[0]=='Y')st[++top]=v1;
		else top--;
	}
	rep(v1,1,in){
		query(st[top],v1);
		ans[v1]=(s[0]=='Y')+'0';
	}
	printf("! %s\n",ans+1);
	cin>>in;
	return 0;
}
posted @ 2025-03-21 17:22  FugiPig  阅读(24)  评论(0)    收藏  举报