CF1354G Find a Gift
题目传送门
分析:
洛谷蓝题???
看来又被开除人籍了
设每个盒子重量为\(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}]\)的重量,\(x\)从0开始枚举
这样第一次出现的不是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);
}