do_while_true

一言(ヒトコト)

「题解」Codeforces 1364E XOR

如果问到 0 了那么直接用这个 0 和其它位置都问一遍就能得到所有数的值。现在问题就是怎么把 0 问出来,有 \(n+173\) 次操作可以用。思考过程大概就是考虑如果现在这个位置不是 0,那么问一圈结果的 \(\&\) 就是这个位置的值 \(x\)。然后问出值是 \(x\) 的一定是 \(x\) 的子集,所以可以递归下去继续找。如果现在序列里只剩两个数,就直接用其中一个数和 \(n\) 个数随机问个多少遍,如果 \(\&\) 为 0 那么一定就是这个位置 0,否则另一个位置 0.

但是这样子实际运行效果比较差,大概 20% 的概率超出询问次数。没想到的事情是:现在已经知道现存的那些数二进制位可能是 1,其它位置一定是 0.可以每次随机现存的两个数 \(x,y\),问出来的结果如果 popcount 比现在的这个的一半还要小,那么就用 \(x\) 去全询问一遍。

找到这样一个 \(x\) 期望次数是 \(\mathcal{O}(1)\) 的,所以询问次数毛估估就 \(2n+\sqrt n+\sqrt{\sqrt n}+...+\mathcal{O}(\log\log n)\),当然能不能过还得看实际测试结果。

#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<ctime>
#include<random>
#include<assert.h>
#include<map>
#define pb emplace_back
#define mp make_pair
#define fi first
#define se second
#define dbg(x) cerr<<"In Line "<< __LINE__<<" the "<<#x<<" = "<<x<<'\n';
#define dpi(x,y) cerr<<"In Line "<<__LINE__<<" the "<<#x<<" = "<<x<<" ; "<<"the "<<#y<<" = "<<y<<'\n';
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>pii;
typedef pair<ll,int>pli;
typedef pair<ll,ll>pll;
typedef pair<int,ll>pil;
typedef vector<int>vi;
typedef vector<ll>vll;
typedef vector<pii>vpii;
typedef vector<pil>vpil;
template<typename T>T cmax(T &x, T y){return x=x>y?x:y;}
template<typename T>T cmin(T &x, T y){return x=x<y?x:y;}
template<typename T>
T &read(T &r){
	r=0;bool w=0;char ch=getchar();
	while(ch<'0'||ch>'9')w=ch=='-'?1:0,ch=getchar();
	while(ch>='0'&&ch<='9')r=r*10+(ch^48),ch=getchar();
	return r=w?-r:r;
}
template<typename T1,typename... T2>
void read(T1 &x,T2& ...y){read(x);read(y...);}
#define flh fflush(stdout)
const int N=2050;
int n,a[N];
int Query(int x,int y){
	cout << "? " << x+1 << ' ' << y+1 << '\n';flh;
	int o;read(o);
	return o;
}
mt19937 rnd(time(NULL));
inline int rd(int a,int b){
	return a+rnd()%(b-a+1);
}
int solve(vi &vec,int las){
	if(vec.size()==1)return vec[0];
	if(vec.size()==2){
		int all=(1<<11)-1;
		for(int i=1;i<=30;i++){
			int x=rd(0,n-1);
			while(vec[0]==x)x=rd(0,n-1);
			all&=Query(vec[0],x);
		}
		if(all)return vec[1];
		return vec[0];
	}
	int len=vec.size(),p=0;
	do{
		int x=rd(0,len-1),y=rd(0,len-1);
		while(x==y)x=rd(0,len-1),y=rd(0,len-1);
		int o=Query(vec[x],vec[y]);
		if(__builtin_popcount(o)<=__builtin_popcount(las)/2){
			p=x;
			break;
		}
	}while(true);
	vi qwq=vec;
	int all=(1<<11)-1;
	for(int i=0;i<len;i++)if(p!=i){
		qwq[i]=Query(vec[p],vec[i]);
		all&=qwq[i];
	}
	if(!all)return vec[p];
	vi ovo;ovo.pb(vec[p]);
	for(int i=0;i<len;i++)if(i!=p&&qwq[i]==all)ovo.pb(vec[i]);
	return solve(ovo,all);
}
signed main(){
	read(n);
	vi vec;
	for(int i=0;i<n;i++)vec.pb(i);
	int x=solve(vec,(1<<11)-1);
	for(int i=0;i<n;i++){
		if(i!=x)a[i]=Query(x,i);
	}
	cout << "! ";
	for(int i=0;i<n;i++)cout << a[i] << ' ';
	return 0;
}
posted @ 2023-02-24 15:32  do_while_true  阅读(13)  评论(0编辑  收藏  举报