AtCoder Regular Contest 070F:Honest Or Unkind

题目传送门:https://arc070.contest.atcoder.jp/tasks/arc070_d

题目翻译

\(n\)个人,其中有\(a\)个人是诚实的,另外\(b\)个是不诚实的。你可以向交互库提问:如果问\(x\)\(y\)号是否诚实\(x\)将怎么回答?如果\(x\)是诚实的,那么\(x\)的回答就是正确的,否则有\(50\)%的几率是他瞎扯淡来唬你的。你的提问次数不能超过\(2n\)次,请确定哪些人是诚实的,哪些不是。如果为无法确定,那么输出Impossible。\(a,b\leqslant 2000\)

题解

如果\(a\leqslant b\)那么就确认不了,我只需要从\(b\)个骗子里叫\(a\)个说真话你就\(GG\)了。

\(a>b\)我们就可以确认,只需要找出一个诚实的人,然后问他这\(n\)个人分别是不是诚实的就行了。假设存在一条链\(x_1->x_2->x_3->...->x_k\),表示\(x_{i-1}\)\(x_i\)是诚实的。这\(k\)个人里面只要任意一个人是诚实的,那么\(x_k\)就必然是诚实的。所以我们可以维护一个栈,如果栈顶说当前枚举的人不是真的,那么两个人里面必然有一个假的,那我两个都不要。因为\(b>a\)所以最后栈里必然会留下一些人并且这些人中肯定有诚实的人,栈顶必然是诚实的,我们再问栈顶的人\(n\)个问题就解决了。

时间复杂度:\(O(n)\)

空间复杂度:\(O(n)\)

代码如下:

#include <cstdio>
using namespace std;
 
const int maxn=4005;
 
int n,a,b,top;
int sta[maxn];
bool ans[maxn];
 
int read() {
    int x=0,f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    return x*f;
}
 
int main() {
    a=read(),b=read(),n=a+b;
    if(a<=b) {puts("Impossible");return 0;}
    for(int i=1;i<=n;i++)
        if(!top)sta[++top]=i;
        else {
            printf("? %d %d\n",sta[top]-1,i-1);
            fflush(stdout);char s[3];
            scanf("%s",s+1);
            if(s[1]=='N')top--;
            else sta[++top]=i;
        }
    int honest=sta[top];
    for(int i=1;i<=n;i++) {
        printf("? %d %d\n",honest-1,i-1);
        fflush(stdout);char s[3];
        scanf("%s",s+1);
        ans[i]=(s[1]=='Y');
    }printf("! ");
    for(int i=1;i<=n;i++)
        printf("%d",ans[i]);
    return 0;
}

转载于:https://www.cnblogs.com/AKMer/p/10169089.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值