zoukankan      html  css  js  c++  java
  • CF1354G Find a Gift

    题面

    英文题面

    题意:有点长,去洛谷上看吧~

    题解:首先挖掘题目的性质:发现如果两个集合都只有一个元素,且询问的结果不是EQUAL,那么小的那个一定就是礼物。那么我们希望能找到一个石头,这样判断起来就能方便很多。

    考虑随意指定30个位置(p(p eq 1)),依次询问((1,p))。如果有返回SECOND的,那么1就一定是礼物。发现由于礼物个数少于(frac{n}{2}),每次询问位置(p)都有至少(frac{1}{2})的概率是石头,那么如果在30次询问后一直没有SECOND,那么我们可以断定1是个石头。考虑只有当这30次询问的位置上都是礼物,且权值都比1小时才有可能犯错,因此这样的犯错概率是小于(frac{1}{2^{30}})的,可以忽略。

    当我们确定了一个石头后,我们就可以进行倍增了。每次询问([1,2^{k-1}])([2^{k-1}+1,2^k]),如果返回EQUAL,那么继续倍增;如果是FIRST,那么区间([2^{k-1}+1,2^k])中就一定有礼物。通过二分查找,我们就能找到最靠左的那个礼物的位置。

    总查询次数是(30+2logn)的,刚好50次。

    代码:

    #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;
    }
    
    
  • 相关阅读:
    【未完成0.0】Noip2012提高组day2 解题报告
    【数论+技巧】神奇的Noip模拟试题第二试 T1 素数统计
    Noip2014 提高组 T2 联合权值 连通图+技巧
    Noip2014 提高组 day1 T1· 生活大爆炸版石头剪刀布
    神奇的Noip模拟试题 T3 科技节 位运算
    博客小谈
    神奇的Noip模拟试题一试 2 排队
    神奇的Noip模拟试题第一试 合理种植 枚举+技巧
    使用Desktop App Converter打包桌面应用程序
    Rust Linking With C Library Functions
  • 原文地址:https://www.cnblogs.com/Purple-wzy/p/13348172.html
Copyright © 2011-2022 走看看