一、题目
二、解法
首先 为 的倍数但不为 的倍数肯定是不行的,因为相对两个数隔了偶数个,所以奇偶性一定不同,所以两个数不同,可以在一开始的时候判掉。
设 为 的对应点, ,有一个性质,就是 ,证明很简单,就是 和 的差异只有两个格子的增减,所以只有这些情况。
可以考虑二分,设 , 算出来的 一开始就异号,所以里面一定有解,我们假设分到 ,判断 算出来的 和 还是 异号,向那边继续分即可,中间算 的时候就判断一下有没有算出 ,算出 了就找到答案了。
讲完这个解法,相信你还有一些问题,比如为什么 一开始就异号,我们把 看作一个连续的函数,现在这段函数的定义域是 ,发现 和 差值一定是 ,所以可以把定义域扩展到 然后 和 一定异号(你看定义呀!),所以 一开始就异号。
真是道神题,贴个代码吧qwq。
#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n;
int ask(int x)
{
cout<<"? "<<x<<endl;int a=read();
cout<<"? "<<x+n/2<<endl;int b=read();
if(a==b)
{
cout<<"! "<<x<<endl;
exit(0);
}
return a-b;
}
int main()
{
n=read();
if(n%4) {printf("! -1\n");return 0;}
int l=1,r=n>>1,tl=ask(l),tr=ask(r);
while(l<=r)
{
int mid=(l+r)>>1,tm=ask(mid);
if(tl*tm<0) r=mid-1,tr=tm;
else l=mid+1,tl=tm;
}
cout<<"! -1"<<endl;
}