Codeforces 835E. The penguin's game(思维题)

http://codeforces.com/problemset/problem/835/E

 

题意:

这是一道交互题

有n个数,其中有2个y,n-2个x

每次你可以询问若干个数的异或和,从而得出y的位置

最开始给出n,x,y

最多询问19次

 

多猪试毒问题:

有1000瓶药,其中只有1瓶是解药,其他的都是毒药

你有一些猪,今天让他们会喝下若干瓶药,所有没有喝到解药的猪会在明天的同一时刻死去

问最少需要多少头猪一定会试出哪瓶是解药

答案是10头

因为不同的数的二进制位至少有一位不相同

10位二进制可表示1000以内的所有的数

让第i头猪喝下所有第i位二进制位为1的药

如果明天第i头猪没有死,就可以确定解药的第i位二进制位为1

 

这道题相当于是有两瓶解药,而且如果喝下两瓶解药会变成毒药

让你构造一种喝药的方案,用至多19头猪找出解药

如果我们能想办法找到一堆药,使得这里面有且只有一瓶解药,那就可以套用上面的方法了

同样的方法,两瓶解药的二进制位至少有一位不同

如果有一头猪没有死,那么它所喝下的药里一定只有一瓶解药,它没喝的药里面也有且仅有一瓶解药

最多用10头猪就可以找到这样的一头猪

它喝的药 和 没喝的药 数量少的那一组里套用一次上面的多猪试毒的方法

就可以找到数量少的那一组 的解药的编号

这一步最多用9头猪

注意一定要用数量少的那一组,这样才能使数量至少减半,变成2^9数量级

(⊙o⊙)…,现在没有猪了,还有一瓶解药,怎么办?

回到第一步,如果有一头猪死了,代表它要么喝下了两瓶解药,要么没喝解药,说明两瓶解药的二进制位相同

如果有一头猪没死,说明两瓶解药的二进制位不同

记录下那些二进制位不同

异或上第一瓶解药的编号即可得到第二瓶解药的编号

 

在这道题里,

解药相当于y,

毒药相当于x,

猪喝下某些药死了相当于询问的位置异或和为 0 或者 x

猪喝下某些药没死相当于询问的位置异或和为 y 或者 x xor y

 

#include<cstdio>
#include<vector>
#include<cstring>

using namespace std;

vector<int>V,U;

bool vis[1001];

int main()
{
    int n,x,y;
    scanf("%d%d%d",&n,&x,&y);
    int siz;
    int tmp; bool tag=false;
    int bit=0;
    int pos;
    int ans=0;
    for(int i=0;i<=9;++i)
    {
        V.clear();
        if(!tag) memset(vis,false,sizeof(vis));
        for(int j=1;j<=n;++j)
            if(j&(1<<i)) V.push_back(j),vis[j]=true;
        siz=V.size();
        if(!siz) continue;
        printf("? %d ",siz);
        for(int j=0;j<siz;++j) printf("%d ",V[j]);
        printf("\n");
        fflush(stdout);
        scanf("%d",&tmp);
        if(tmp==y || tmp==(x^y)) 
        {
            bit+=1<<i;
            if(!tag) 
            {
                tag=true; 
                pos=i;
                if(siz<n-siz) U=V,ans=1<<i;
                else 
                {
                    for(int j=1;j<=n;++j)
                        if(!vis[j]) U.push_back(j);
                }
            }
        }
    }
    int m=U.size();
    for(int i=0;i<=9;++i)
    {
        if(pos==i) continue;
        V.clear();
        for(int j=0;j<m;++j)
            if(U[j]&(1<<i)) V.push_back(U[j]);
        siz=V.size();
        if(!siz) continue;
        printf("? %d ",siz);
        for(int j=0;j<siz;++j) printf("%d ",V[j]);
        printf("\n");
        fflush(stdout);
        scanf("%d",&tmp);
        if(tmp==y || tmp==(x^y)) ans+=1<<i;
    }
    printf("! %d %d",min(ans,ans^bit),max(ans,ans^bit));
}

 

posted @ 2018-02-11 17:43  TRTTG  阅读(389)  评论(0编辑  收藏  举报