题目描述
题解
如果每个元素被都访问到奇数次则可以知道异或和,否则不知道。
就相当于给定一些向量的话,能否线性表出一个向量,其中表出方式为异或。
因此我们考虑如果目前有 i i i 个元素为奇数次被访问了,把这 i i i 个元素放在一个集合,每次在这个集合里选出 j j j 个元素踢出去,然后再从集合外选 k − j k-j k−j 个元素放进去。
因此只要 bfs \text{bfs} bfs 这个过程即可。
效率: O ( n k ) O(nk) O(nk) 。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=505;
int n,k,f[N],g[N],s;
queue<int>p,q;
int main(){
scanf("%d%d",&n,&k);
q.push(k);f[k]=1;
for (;!q.empty();){
int u=q.front();q.pop();
for (int i=0,v;i<=k && i<=u;i++){
if (k-i>n-u) continue;
v=u-i+k-i;if (v && v<=n && !f[v])
q.push(v),f[v]=f[u]+1,g[v]=u;
}
}
if (!f[n]){
puts("-1");return 0;
}
for (int i=1;i<=n;i++) q.push(i);
for (int i=n,j,u;i;i=g[i]){
u=g[i];j=(u+k-i)>>1;
printf("?");
for (int l=0;l<k-j;l++)
printf(" %d",q.front()),
p.push(q.front()),q.pop();
for (int l=0;l<j;l++)
printf(" %d",p.front()),
q.push(p.front()),p.pop();
puts("");fflush(stdout);
scanf("%d",&u);s^=u;
}
printf("! %d\n",s);fflush(stdout);
return 0;
}