【杂题】[ARC070F] Honest Or Unkind【交互】

Description

这是一道交互题
有A+B个人,编号从0~A+B-1,其中有A个人是诚实的,B个人是居心叵测的。
你想知道每个人是诚实的还是居心叵测的。
询问可以用二元组(i,j)表示,代表问编号为i的人 编号为j的人是否诚实。
诚实的人总会说真话,你不知道居心叵测的人会如何回答。(你可以理解为,交互库是自动适应的)
你只知道A,B,需要在2N次询问内得到答案,或者判断居心叵测的人一定存在一种回答方法使得你无论怎么问都存在两种或以上可能性,输出Impossible。
A,B<=2000

Solution

首先考虑怎么样是无解的。
其实很简单,就是当B>=A时
只要B>=A,那么从中挑出A个人假扮成好人,互相证明对方是真的,然后一起指证真的那A个人是假的,那么这样永远也不可能问出来。
那么现在A>B,该怎么做呢?

如果我们确定了一个人是真的,那么只需要问他一遍所有人就好了。

可以发现,如果我们问x 第y号人是否诚实,得到的回答是否定的话,那么x,y中必有一人是居心叵测的,我们可以直接将这两个人排除,这样剩余的人中诚实的人数仍旧大于居心叵测的人数。
具体来说,我们可以维护一个栈,从前向后看每一个人,询问栈顶的人新扫到的这个人是否诚实,是则入栈,否则将栈顶和这个人一起排除。
剩下栈中的人每个人都承认在它上方的那个人是诚实的,由于栈中至少一人是诚实的,因此栈顶的人一定诚实。
问他一遍所有人即可。

Code

Atcoder的交互格式有毒...

endl可以自动刷新输出缓冲区

#include <bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define N 5005
using namespace std;
int st[N],ans[N];
bool query(int x,int y)
{
    cout<<"? "<<x<<" "<<y<<endl;
    char ch[5];
    scanf("%s",ch+1);
    return (ch[1]=='Y');
}
int main()
{
    int a,b;
    scanf("%d%d",&a,&b);
    if(a<=b) cout<<"Impossible"<<endl;
    else
    {
        int top=0;
        fo(i,0,a+b-1)
        {
            if(!top) st[++top]=i;
            else 
            {   
                if(!query(st[top],i)) st[top--]=0;
                else st[++top]=i;
            }
        }
        fo(i,0,a+b-1) ans[i]=query(st[top],i);
        cout<<"! ";
        fo(i,0,a+b-1) cout<<ans[i];
        cout<<endl;
    }
    return 0;   
}

猜你喜欢

转载自www.cnblogs.com/BAJimH/p/11013057.html