E.Lost Array (思维 bfs)
题目大意
交互题。给定 n ( 1 ≤ n ≤ 500 ) n(1\leq n \leq 500) n(1≤n≤500)个元素一个数组,你每一次询问可以获得其中 k ( 1 ≤ k ≤ n ) k(1\leq k \leq n) k(1≤k≤n)个数的异或值,要求询问次数不超过 500 500 500次计算出 n n n个数的异或值。
题解
首先考虑异或的两个经典性质
- x x x^ x = 0 x=0 x=0
-
x
x
x^
0
=
x
0=x
0=x
因此,对于一个数来说,异或奇数次的值都是相同用的,偶数次同理。
我们考虑将每一次的询问结果异或起来,就只要求每一个数都被问奇数次就能得到答案。这样其实就等价于一个经典问题,有 n n n枚正面朝上的硬币,你每次可以选择 k k k个硬币进行翻转,怎么操作才能让所有硬币反面朝上。直接枚举反转中正面朝上的个数bfs就行了。
参考代码
#include <bits/stdc++.h>
using namespace std;
#define ls o<<1
#define rs o<<1|1
#define fi first
#define se second
typedef long long ll;
typedef pair<int,int> pii;
const int maxn=500+10;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
int dp[maxn][maxn];
pii pre[maxn][maxn];
int pre2[maxn][maxn];
int n,k;
deque<int> q[2];
void bfs(int a,int b){
queue<pii> q;
q.push({a,b});
while(!q.empty()){
int u=q.front().fi,v=q.front().se;q.pop();
for(int i=0;i<=u;i++){
if(k-i>v||k-i<0) continue;
int nxtu=u-i+k-i,nxtv=v-k+2*i;
if(dp[nxtu][nxtv]==-1){
dp[nxtu][nxtv]=dp[u][v]+1;
q.push({nxtu,nxtv});
pre[nxtu][nxtv]={u,v};
pre2[nxtu][nxtv]=i;
}
}
}
}
int ask(int num1,int num2){
printf("? ");
fflush(stdout);
for(int i=1;i<=num1;i++){
int u=q[0].front();q[0].pop_front();
q[1].push_back(u);
printf("%d ",u);
fflush(stdout);
}
for(int i=1;i<=num2;i++){
int u=q[1].front();q[1].pop_front();
q[0].push_back(u);
printf("%d ",u);
fflush(stdout);
}
puts("");
int res;
scanf("%d",&res);
fflush(stdout);
return res;
}
void solve(){
scanf("%d %d",&n,&k);
memset(dp,-1,sizeof(dp));
dp[n][0]=0;
pre[n][0]={0,0};
bfs(n,0);
for(int i=1;i<=n;i++) q[1].push_back(i);
int ans=0;
if(dp[0][n]==-1){ puts("-1");return ;}
else {
int x=0,y=n;
while(pre[x][y]!=make_pair(0,0)){
int nxtx=pre[x][y].fi,nxty=pre[x][y].se;
ans^=ask(k-pre2[x][y],pre2[x][y]);
x=nxtx;y=nxty;
}
}
printf("! %d\n",ans);
fflush(stdout);
}
int main(){
clock_t t1=clock();
#ifndef ONLINE_JUDGE
// freopen("in.in", "r", stdin);
// freopen("out.out","w",stdout);
#endif
// int T;scanf("%d",&T);while(T--)
solve();
end:
cerr<<"Time used "<<clock()-t1<<" ms"<<endl;
return 0;
}