Codeforces 1158E - Strange device(交互)

一个有点烦的 \(8\log n\) 的做法。

大致想法大家都一样:以 \(1\) 为根,然后先问出每个点深度,再问出每个点的父亲。

首先先用一个 log 的做法问出树高,具体做法是直接令根节点的 \(f\) 为二分出的 \(mid\),看能否覆盖所有点即可,记最大深度为 \(mxdep\)。可以在二分过程中顺带着求出深度为 \(mxdep\) 的点集。

先考虑怎么问每个点的深度,我们分层,假设现在已经对于每个 \(i\in[0,\dfrac{mxdep}{2^k}]\) 已经知道了哪些点深度在 \([i·2^k,(i+1)·2^k-1]\) 这段区间内,以及深度等于 \(i·2^k,(i+1)·2^k-1\) 的点有哪些(方便起见,我们记这三个信息分别为 \(st_i,top_i,bot_i\))。考虑如何将这些长度为 \(2^k\) 的大区间划分为 \(2^{k-1}\) 的小区间(即,对于每个 \(i\in[0,\dfrac{mxdep}{2^{k-1}}]\) 求出深度在 \([i·2^{k-1},(i+1)·2^{k-1}-1]\) 的点中的点 \(st'_i\)\(top'_i,bot'_i\) 的定义类似),我们先对于每个 \(i\in[0,\dfrac{mxdep}{2^k}]\) 且是偶数的 \(i\),令 \(top_i\) 中点的 \(f\)\(2^{k-1}-1\),其他点的 \(f\) 为零,这样,对于偶数 \(i\)\(st_i\) 中那些被覆盖的点的深度就在 \(st'_{2i}\) 中,没被覆盖的点的深度就在 \(st'_{2i+1}\) 中。对于奇数也同样处理。这样我们求出了 \(st'\),但是我们还不知道 \(top'\)\(bot'\)。考虑对于每个 \(i\in\mathbb{Z}\),将 \(st'_{2i}\) 中的点的 \(f\) 设为 \(1\),其他点的 \(f\)\(0\),这样对于 \(st_{2i+1}\) 中的所有点,那些被覆盖的点要么在 \(top'_{2i+1}\) 中,要么在 \(bot'_{2i+1}\) 中,而显然 \(bot'_{2i+1}=bot_i\),因此可以求出 \(top'_{2i+1}\),同时因为 \(top'_{2i}=top_i\),这样可以知道所有 \(top'\)。接下来考虑怎么求 \(bot'\),我们将 \(top'_{2i}\) 的点的 \(f\) 都设为 \(2^{k-1}-2\),这样 \(st'_{2i}\) 中没被覆盖的点就一定在 \(bot'_{2i}\) 中,再根据 \(bot'_{2i+1}=bot_i\) 求出所有 \(bot'\)。这样我们使用了 \(4\) 次询问从第 \(k\) 层推到第 \(k-1\) 层。总询问次数 \(4\log n\)

接下来考虑怎么求每个点的父亲,这部分其实还挺 trivial,对于 \(k=0,1,2\),我们每次给深度 \(\bmod 3=k\) 的点确定父亲,这个模型相当于我们有两组集合 \(S_i,T_i\),我们已经确定 \(T_i\) 中每个点的父亲都在 \(S_i\) 中。考虑如何划分为更小的子问题,显然 \(|S_i|=1\) 的点直接已经确定了,否则令 \(S_i\) 中前一半元素的 \(f\)\(1\),这样 \(T_i\) 中被覆盖的点的父亲就在 \(S_i\) 中,没被覆盖就在后一半,继续递归即可。又因为我们对 \(\bmod 3\) 进行了分组,因此不同组的询问不会影响。这样单次需要 \(\log n\) 个询问,而我们要跑三次,所以是 \(3\log n\)

总共是 \(8\log n\)。代码实现起来有点细节。

const int MAXN=1000;
int n;
vector<bool>query(vector<int>v){
	printf("?");for(int x:v)printf(" %d",x);printf("\n");fflush(stdout);
	string s;cin>>s;vector<bool>res(n);
	for(int i=0;i<n;i++)res[i]=s[i]-'0';
	for(int i=0;i<n;i++)if(v[i])res[i]=1;
	return res;
}
int dep[MAXN+5],fa[MAXN+5],mxdep;vector<int>qv[MAXN+5];
void calc_dep(vector<tuple<vector<int>,vector<int>,vector<int> > >v,int k){
	//(total,top,bottom)
	if(k==0){for(int i=0;i<v.size();i++)for(int x:get<0>(v[i]))dep[x]=i;return;}
	if(k==1){
		for(int i=0;i<v.size();i++){
			for(int x:get<1>(v[i]))dep[x]=i*2;
			for(int x:get<2>(v[i]))dep[x]=i*2+1;
		}return;
	}
	vector<tuple<vector<int>,vector<int>,vector<int> > >nv;
	vector<int>vec(n);vector<bool>tmp,res(n); 
	for(int i=0;i<v.size();i+=2)for(int x:get<1>(v[i]))vec[x]=((1<<k-1)-1);
	tmp=query(vec);
	for(int i=0;i<v.size();i+=2)for(int x:get<0>(v[i]))if(tmp[x])res[x]=1;
	for(int i=0;i<n;i++)vec[i]=0;
	for(int i=1;i<v.size();i+=2)for(int x:get<1>(v[i]))vec[x]=((1<<k-1)-1);
	tmp=query(vec);
	for(int i=1;i<v.size();i+=2)for(int x:get<0>(v[i]))if(tmp[x])res[x]=1;
	for(int i=0;i<v.size();i++){
		vector<int>v0,v1;
		for(int x:get<0>(v[i])){
			if(res[x]==0)v0.pb(x);
			else v1.pb(x);
		}
		if(!v0.empty()){
			nv.pb(mt(v1,get<1>(v[i]),vector<int>{}));
			nv.pb(mt(v0,vector<int>{},get<2>(v[i])));
		}else nv.pb(mt(v1,get<1>(v[i]),get<2>(v[i])));
	}
	for(int i=0;i<n;i++)vec[i]=0;
	for(int i=0;i<nv.size();i+=2)for(int x:get<0>(nv[i]))vec[x]=1;
	res=query(vec);
	for(int i=1;i<nv.size();i+=2){
		static bool vis[MAXN+5];memset(vis,0,sizeof(vis));
		vector<int>vv;
		for(int x:get<2>(nv[i]))vis[x]=1;
		for(int x:get<0>(nv[i]))if(res[x]&&!vis[x])vv.pb(x);
		get<1>(nv[i])=vv;
	}
	for(int i=0;i<n;i++)vec[i]=0;
	for(int i=0;i<nv.size();i+=2)for(int x:get<1>(nv[i]))vec[x]=(1<<(k-1))-2;
	res=query(vec);
	for(int i=0;i<nv.size();i+=2){
		static bool vis[MAXN+5];memset(vis,0,sizeof(vis));
		vector<int>vv;
		for(int x:get<1>(nv[i]))vis[x]=1;
		for(int x:get<0>(nv[i]))if(!res[x]&&!vis[x])vv.pb(x);
		if(get<2>(nv[i]).empty())get<2>(nv[i])=vv;
	}
	calc_dep(nv,k-1);
}
void calc_fa(vector<pair<vector<int>,vector<int> > >_v){
	vector<pair<vector<int>,vector<int> > >v,nv;
	for(auto t:_v){
		if(t.fi.size()==1){for(int x:t.se)fa[x]=t.fi[0];}
		else v.pb(t);
	}
	if(v.empty())return;
	vector<int>vec(n);vector<bool>res;
	for(int i=0;i<v.size();i++){
		int mid=v[i].fi.size()/2;
		for(int j=0;j<mid;j++)vec[v[i].fi[j]]=1;
	}res=query(vec);
	for(int i=0;i<v.size();i++){
		vector<int>A,B;int mid=v[i].fi.size()/2;
		for(int j=0;j<mid;j++)A.pb(v[i].fi[j]);
		for(int x:v[i].se)if(res[x]==1)B.pb(x);
		nv.pb(mp(A,B));A.clear();B.clear();
		for(int j=mid;j<v[i].fi.size();j++)A.pb(v[i].fi[j]);
		for(int x:v[i].se)if(res[x]==0)B.pb(x);
		nv.pb(mp(A,B));
	}calc_fa(nv);
}
int main(){
	scanf("%d",&n);
	int l=0,r=n-1;vector<int>bot;
	while(l<=r){
		int mid=l+r>>1;vector<int>v(n);v[0]=mid;
		vector<bool>res=query(v);vector<int>v0;
		for(int i=0;i<n;i++)if(!res[i])v0.pb(i);
		if(v0.empty())r=mid-1;
		else mxdep=mid,l=mid+1,bot=v0;
	}
	mxdep++;int K=0;while((1<<K)<=mxdep)++K;
	if(mxdep==1){printf("!\n");for(int i=2;i<=n;i++)printf("1 %d\n",i);fflush(stdout);return 0;}
	vector<int>vec;for(int i=0;i<n;i++)vec.pb(i);
	calc_dep({mt(vec,vector<int>{0},bot)},K);
	for(int x:bot)dep[x]=mxdep;
	for(int i=0;i<n;i++)qv[dep[i]].pb(i);
	for(int i=0;i<3;i++){
		vector<pair<vector<int>,vector<int> > >v;
		for(int j=i;j<mxdep;j+=3)v.pb(mp(qv[j],qv[j+1]));
		calc_fa(v);
	}
	printf("!\n");
	for(int i=1;i<n;i++)printf("%d %d\n",fa[i]+1,i+1);
	fflush(stdout);
	return 0;
}
posted @ 2023-05-16 15:45  tzc_wk  阅读(25)  评论(0编辑  收藏  举报