https://codeforces.com/contest/1486/problem/C2
思路倒是不难想阿。上次的教训一看就是个二分把。
一般的二分没包括mid,这题需要包括mid。每次包括mid之后看第二大值的问题有没有变。然后就可以二分了。
C1可能变区间mid去做,c2的话其实发现每次都带着最开始问的不变的第二大pos和l,r去比较。
但是有个坑。我比赛的时候一直wa1,赛后也一直wa2.
就是[l,l][r,r]是不能出现的
所以开始的时候有个边界。
下面代码中的注释中有写
虽然if判了p>1,但是提前询问了。就是非法询问..
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e5;
typedef long long LL;
inline LL read(){LL x=0,f=1;char ch=getchar(); while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;}
LL ask(LL l,LL r){
cout<<"? "<<l<<" "<<r<<endl;
LL pos;cin>>pos;
return pos;
}
int main(void)
{
LL n;cin>>n;
LL p=ask(1,n);
//LL t=ask(1,p);可能产生不符合条件的询问,下面也是ask放右边
if(p>1&&ask(1,p)==p){///答案在左边
LL l=1;LL r=p-1;
while(l<r){
LL mid=(l+r+1)/2;
LL now=ask(mid,p);
if(now==p){
l=mid;
}
else r=mid-1;
}
cout<<"! "<<l<<endl;
}
else{///答案在右边
LL l=p+1;LL r=n;
while(l<r){
LL mid=(l+r)/2;
LL now=ask(p,mid);
if(now==p){
r=mid;
}
else l=mid+1;
}
cout<<"! "<<l<<endl;
}
return 0;
}