题面c++
英文题面git
题意:有点长,去洛谷上看吧~spa
题解:首先挖掘题目的性质:发现若是两个集合都只有一个元素,且询问的结果不是EQUAL,那么小的那个必定就是礼物。那么咱们但愿能找到一个石头,这样判断起来就能方便不少。code
考虑随意指定30个位置\(p(p\neq 1)\),依次询问\((1,p)\)。若是有返回SECOND的,那么1就必定是礼物。发现因为礼物个数少于\(\frac{n}{2}\),每次询问位置\(p\)都有至少\(\frac{1}{2}\)的几率是石头,那么若是在30次询问后一直没有SECOND,那么咱们能够判定1是个石头。考虑只有当这30次询问的位置上都是礼物,且权值都比1小时才有可能犯错,所以这样的犯错几率是小于\(\frac{1}{2^{30}}\)的,能够忽略。ci
当咱们肯定了一个石头后,咱们就能够进行倍增了。每次询问\([1,2^{k-1}]\)和\([2^{k-1}+1,2^k]\),若是返回EQUAL,那么继续倍增;若是是FIRST,那么区间\([2^{k-1}+1,2^k]\)中就必定有礼物。经过二分查找,咱们就能找到最靠左的那个礼物的位置。get
总查询次数是\(30+2logn\)的,恰好50次。it
代码:class
#include<bits/stdc++.h> using namespace std; #define re register int #define F(x,y,z) for(re x=y;x<=z;x++) #define FOR(x,y,z) for(re x=y;x>=z;x--) typedef long long ll; #define I inline void #define IN inline int #define C(x,y) memset(x,y,sizeof(x)) #define STS system("pause") template<class D>I read(D &res){ res=0;register D g=1;register char ch=getchar(); while(!isdigit(ch)){ if(ch=='-')g=-1; ch=getchar(); } while(isdigit(ch)){ res=(res<<3)+(res<<1)+(ch^48); ch=getchar(); } res*=g; } mt19937 rnd(time(0)); char c[10]; int T,n,m,ans,v[1010],p; IN Rand(int Mod){ re res=rnd();if(res<0)res=-res;res%=Mod;return res; } I getit(int x,int y,int len){ if(x==y)return cout<<"! "<<x<<endl,void(); re mid=(x+y)>>1,ln=(len+1)>>1; cout<<"? "<<ln<<" "<<ln<<endl; F(i,x-ln,x-1)cout<<i<<" ";cout<<endl; F(i,x,mid)cout<<i<<" ";cout<<endl; cout.flush();cin>>c+1;if(c[1]=='W')exit(0); if(c[1]=='F')getit(x,mid,ln); else getit(mid+1,y,len-ln); } int main(){ srand(time(0)); cin>>T; while(T--){ cin>>n>>m;C(v,0);ans=0; F(i,1,min(30,n-1)){ while(1){ p=Rand(n-1)+2;if(!v[p])break; } v[p]=1; cout<<"? 1 1"<<endl<<"1"<<endl<<p<<endl;cout.flush(); cin>>c+1;if(c[1]=='W')return 0; if(c[1]=='S'){ans=1;break;} } if(ans){cout<<"! "<<ans<<endl;cout.flush();continue;} re r=1,mid; while((r<<1)<=n){ r<<=1;mid=r>>1;cout<<"? "<<mid<<" "<<mid<<endl; F(i,1,mid)cout<<i<<" ";cout<<endl; F(i,mid+1,r)cout<<i<<" ";cout<<endl; cout.flush();cin>>c+1;if(c[1]=='W')return 0; if(c[1]=='F'){ getit(mid+1,r,mid);ans=1; break; } } if(ans)continue; getit(r+1,n,n-r); } return 0; }