题目描述
题解
如果每个元素被都访问到奇数次则可以知道异或和,否则不知道。
就相当于给定一些向量的话,能否线性表出一个向量,其中表出方式为异或。
因此我们考虑如果目前有 $i$ 个元素为奇数次被访问了,把这 $i$ 个元素放在一个集合,每次在这个集合里选出 $j$ 个元素踢出去,然后再从集合外选 $k-j$ 个元素放进去。
因此只要 $ ext{bfs}$ 这个过程即可。
效率: $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 ",s);fflush(stdout); return 0; }