对于这道题,交互类型,可能有些生疏,但是细看还是可做的。
好人就会说真话,而坏人视情况说,即他说的话你无法全信。
首先考虑什么时候无解,显然当
的时候就无解了,因为这个时候
个坏人中的
个人是可以假装那
个好人的,他们互相指认为好人并且把其他人都指认为坏人,你就永远无法分辨出他们和真正的好人。
然后考虑
,我们的思路是在保持
的性质不变的情况下将
的规模缩小,同时均摊下来每两次查询确定一个人,我们可以基于这样的一个策略:
显然我们可以先找出来一个好人,然后由他来得到其他人的身份。
这样来说我们怎么让好人可以快速指认好人呢?
两两互相指认么?
貌似这样我们需要
的次数。
我们尝试一下,对一个询问进行剖析:
如果
指认
是好人,如果
是好人,那么
也是好人,如果
是坏人,那么
的身份无法确认。
如果
指认
是坏人,那么非常清楚,
和
中必然至少有一个人是坏人,
是好人的话,
就是坏人,
是坏人的话,那就是坏人!
考虑到
这一性质,所以我们可以暴力一点,找好人的时候可以连坐杀人(
怎么找呢?维护一个数据结构。
能做到这样的,我找一个人问另外一个人,另外一个人问另另外一个人。
然后存在 指认坏人 的情况的,两个人都不考虑成为最后人选,最好是这个最后人选应该是最优的答案。
那么因为
我们同时删去
人,仍能保持
。
所以在我们捏造的这个链上,只存在 指认为好人的情况,即使前面都是坏人,只要有一个节点出现好人,那么之后的节点只会是好人。
嗯,然后最后一个节点就是最后人选,拿他去问
次就可以了。
这个数据结构是什么呢?其实用什么无所谓(((
我选择用栈。
维护一个栈,依次扫过每个点,如果栈为空就把它入栈,否则询问栈顶这个人是不是好人。
如果是,就是入栈,如果不是,就弹栈(刚刚扫过的节点都没入栈呢)。
#include <bits/stdc++.h>
using namespace std;
#define il inline
#define INF 0x3f3f3f3f
#define cl(a, b) memset(a, b, sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
char s[10];
void query(int x, int y)
{
printf("? %d %d\n", x, y);
fflush(stdout);
scanf("%s", s);
}
int flag[6020];
stack<int> q;
int main()
{
int a, b;
scanf("%d %d", &a, &b);
if (a <= b)
{
printf("Impossible\n");
return 0;
}
int n = a + b;
for (int i = 0; i < n; i++)
{
if (q.empty())
{
q.push(i);
continue;
}
query(q.top(), i);
if (s[0] == 'Y') q.push(i);
else q.pop();
}
for (int i = 0; i < n; i++)
{
query(q.top(), i);
if (s[0] == 'Y') flag[i] = 1;
}
printf("! ");
for (int i = 0; i < n; i++) printf("%d", flag[i]);
puts("");
fflush(stdout);
return 0;
}