CF1354G Find a Gift
阿新 • • 發佈:2020-07-17
題目傳送門
分析:
洛谷藍題???
看來又被開除人籍了
設每個盒子重量為\(w\)
首先判斷1號盒子裡面是不是禮物
從後面隨機抽大概30個盒子進行比較,如果有\(w_1<w_x\),那麼1號盒子裡面必定是禮物,直接結束程式
如果全是\(w_1\geq w_x\),那麼我們可以認為1號盒子裡面就是石頭
由於禮物數量\(k\leq \frac{n}{2}\),如果說1號盒子是禮物且我們抽30個盒子全部被反饋\(w_1\geq w_x\)
這個概率小於\(2^{-30}\),可以判定為不可能
(如果你是10連全綵的歐皇當我沒說
接下來使用倍增比較\([1,2^x]\)與\([2^x+1,2^{x+1}]\)
這樣第一次出現的不是equal的反饋必定為second,說明\([2^x+1,2^{x+1}]\)這個區間裡第一次出現了禮物,而\([1,2^x]\)裡面全是石頭
後面具體位置二分判斷即可
詢問次數為\(30+2logn\),不會大於\(50\)
#include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<queue> #include<set> #include<map> #include<vector> #define maxn 1000005 #define INF 0x3f3f3f3f using namespace std; inline int getint() { int num=0,flag=1;char c; while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1; while(c>='0'&&c<='9')num=num*10+c-48,c=getchar(); return num*flag; } int n; char s[maxn]; inline char ask(int l,int r,int L,int R) { printf("? %d %d\n",r-l+1,R-L+1); for(int i=l;i<=r;i++)printf("%d ",i);puts(""); for(int i=L;i<=R;i++)printf("%d ",i);puts(""); fflush(stdout); scanf("%s",s);return s[0]; } int main() { int T=getint(); srand(114514); while(T--) { fflush(stdout); n=getint(),getint(); int x=rand()%(n-1)+2,flg=0; for(int i=1;i<=30;i++) { if(ask(1,1,x,x)=='S'){puts("! 1"),flg=1;break;} x=rand()%(n-1)+2; } if(flg)continue; for(x=1;x*2<=n;x*=2)if(ask(1,x,x+1,2*x)!='E')break; int l=x+1,r=min(2*x,n); while(l<r) { int mid=(l+r)>>1; if(ask(1,mid-l+1,l,mid)=='E')l=mid+1; else r=mid; } printf("! %d\n",l); } fflush(stdout); }