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\),所以我们可以做一个栈,保证坏人在好人底下,那就可以得到如下策略:
因为 \(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;
}

浙公网安备 33010602011771号