Codeforces Round #503 (by SIS, Div. 2) D. The hat(交互题)

题目链接:http://codeforces.com/contest/1020/problem/D

题意描述:

这是一个交互题,互交题就是你要输出一些问题,评测机就会回答你一些问题

你要在规定的提问次数中找到问题答案并回答后return 0;

这个题目是给出一个偶数n(n<=1e5),n个人编号1到n坐一圈,编号i的对面是编号i+n/2的人(i<=n/2),反过来也是一样

每个人手上有一个数字ai(ai<=1e9),规则是任意相邻两个人的数字之差为1或-1,1和n也满足这个限制

现在你有询问方式《? x》,机器会回答你x编号的人手上的数字。

你的任务是找到任意一个人跟其对面人手上数字相同,并回答《! ans》,ans为满足条件的人

如果没有这样的人,回答《! -1》

题目分析:

考虑n=4k+2的情况,每个人跟其对面的人之间相差2k+1个人,因为任意相邻两个人的数字之差为1或-1,而且2k+1为奇数,那么对面的人跟他经过奇数次+1或-1之后现在不可能是跟他相同数字,所以n=4k+2的情况一定无解。

考虑n=4k的情况,每个人跟其对面的人之间相差2k个人,同上,可能会有解,实际上是必定有解:

Codeforces Round #503 (by SIS, Div. 2) D. The hat(交互题)_第1张图片

图中a[i]表示每个人拥有的数字,d[i]表示第i个人的数字跟对面的人数字之差,

可以发现d[i]和d[i+1]之间的差值只能是+2 -2或0,并且对面两个人之间的d[i]值是相反数,d[i]一定是偶数

题目要求的答案就是di=0的这些点,设位置l和位置r初始相对,由上可知d[l] = -d[r]

那么显然在任意两个异号的d[l]和d[r]之间必定存在d[ans]的值为0,二分即可找到ans,且ans必定存在。

AC代码:

#include
using namespace std;
int n,m,ans[3];
inline int across(int o){    //找到位置o的对面的位置id
    return (o+n/2-1)%n+1;    //-1取模再+1,结果范围在1到n
}
inline int query(int o){
    printf("? %d\n? %d\n",o,across(o));
    fflush(stdout);
    scanf("%d%d",&ans[1],&ans[2]);
    if(ans[1] == ans[2]){   //询问到答案,输出并退出程序
        printf("! %d\n",o);
        fflush(stdout);
        exit(0);
    }
    return ans[1]>ans[2]?1:-1;
}
int main(){
    scanf("%d",&n);
    if(n%4){            //n不是4的倍数无解
        printf("! -1\n");
        fflush(stdout);
        return 0;
    }
    int T=30,l=1,r=1+n/2,mid,dl,dr,dm;
    dl=query(l);dr=-dl;
    while(l+1>1;
        dm=query(mid);
        if(dl<0){
            if(dm<0)l=mid;  //dm与dl同号则更新l
            else r=mid;
        }else if(dr<0){
            if(dm<0)r=mid;  //dm与dr同号则更新r
            else l=mid;
        }
    }
    query(r);
    query(l);
    return 0;
}

 

你可能感兴趣的:(交互题)