ARC070F - HonestOrUnkind 题解

题目链接:F - HonestOrUnkind

题目大意:有 \(n=A+B\) 个人,其中 \(A\) 个人诚实,\(B\) 个人不诚实,你可以向 \(x\) 询问 \(y\) 是否诚实,在 \(2n\) 次询问内求出每一个人是否诚实,无解输出 Impossible\(A,B\leq 2000\)


题解:若 \(A\leq B\) 那么如果有一个大小为 \(A\) 的不诚实群体指认诚实群体不诚实,指认自己的群体诚实(即模仿诚实的群体),那么就不行了。

我们询问 ? x y,若返回 Y,那么显然两人都诚实或两人都不诚实,若返回 N,那么两人至少一人不诚实。

因为 \(A>B\),所以我们发现 N 直接把两个人一起甩掉就好了,最后肯定至少留下一个诚实的。

我们可以维护一个栈,从 \(1\sim n\) 扫,每一次用栈顶人询问当前人,如果回答 N 就跳过这个人并把栈顶弹掉,否则压栈。

操作次数 \(2n\),时间复杂度 \(O(n)\)

#include <cstdio>
const int Maxn=2000;
int n;
int A,B;
bool query(int x,int y){
	x--,y--;
	printf("? %d %d\n",x,y);
	fflush(stdout);
	char s[5];
	scanf("%s",s);
	return (*s)=='Y';
}
int ans[Maxn<<1|5];
int st[Maxn<<1|5],st_top;
int main(){
	scanf("%d%d",&A,&B);
	if(A<=B){
		puts("Impossible");
		return 0;
	}
	n=A+B;
	for(int i=1;i<=n;i++){
		if(st_top==0){
			st[++st_top]=i;
			continue;
		}
		if(query(st[st_top],i)){
			st[++st_top]=i;
		}
		else{
			st_top--;
		}
	}
	int u=st[st_top];
	for(int i=1;i<=n;i++){
		if(u==i){
			ans[i]=1;
			continue;
		}
		if(ans[i]==0){
			ans[i]=query(u,i);
		}
	}
	printf("! ");
	for(int i=1;i<=n;i++){
		printf("%d",ans[i]);
	}
	puts("");
	return 0;
}
posted @ 2022-02-05 21:29  with_hope  阅读(89)  评论(0编辑  收藏  举报