ABC313D

发布时间 2023-11-12 13:15:17作者: mRXxy0o0

题意

有一个包含 \(N\) 个元素为 \(0\)\(1\) 的序列,你最多可以提问 \(N\) 次,每次询问 \(K\) 个不同下标所代表的元素的异或和。当可以唯一确定这个序列时,输出它。

分析

观察到限制条件 \(1\le K<N\),不妨从边界入手思考。\(K=1\) 时不用说,考虑一下 \(K=N-1\) 时。

很容易发现,问 \(N\) 次,只有一种问法。例如 \(N=4,K=3\) 时,问题就是 \((234),(134),(124),(123)\)

在满足题目条件 \(K\) 为奇数的前提下,是一定可以推断出每一个元素的值的,只需要把所有回答异或起来就可以得到整个序列的异或和。然后依次与每个回答异或,就可以还原出原序列了。

据此,我们可以把整个序列分成数个长为 \(K+1\) 的段,分别求解。

对于最后的一小部分,可以通过询问要求的和另外 \(K-1\) 个已知元素的异或和得到。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e3+10;
int n,k,a[N],b[N];
inline void solve(int l,int r){
	int s=0;
	for(int i=l;i<=r;++i){
		cout<<"?";
		for(int j=l;j<=r;++j){
			if(i==j) continue;
			cout<<" "<<j;
		}
		cout<<endl;
		cin>>a[i];
		s^=a[i];
	}
	for(int i=l;i<=r;++i) b[i]=s^a[i];
}
int main(){
	cin>>n>>k;
	for(int i=1;i<=n;++i){
		if(i+k<=n){
			solve(i,i+k);
			i+=k;
		}
		else{
			int res=0;
			cout<<"?";
			for(int j=1;j<k;++j){
				cout<<" "<<j;
				res^=b[j];
			}
			cout<<" "<<i<<endl;
			cin>>b[i];
			b[i]^=res;
		}
	}
	cout<<"!";
	for(int i=1;i<=n;++i) cout<<" "<<b[i];
	cout<<endl;
	return 0;
}