題目鏈接: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個人,同上,可能會有解,實際上是必定有解:
圖中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<bits/stdc++.h>
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<r){
mid=(l+r)>>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;
}