Codeforces LATOKEN Round 1 (Div. 1 + Div. 2) E. Lost Array

E. Lost Array

题意

给你 n n n 个数,每次可以询问 k ( 1 ≤ k ≤ n ) k(1 \le k \le n) k(1kn) 个数的异或和,要求用最少的询问得到所有 n n n 个数的异或和。如果没有可能的方案,则输出 -1

题解

  • 异或奇数次等价异或一次,异或偶数次等价于没有异或;
  • 这个问题等价于一个经典的问题,有 n n n 枚正面朝上的硬币,每次可以选择 k k k 个硬币翻转,怎么用最少的操作次数让所有硬币反面朝上;
  • 枚举翻转中正面朝上的个数即可。

代码

#include <bits/stdc++.h>
#define rep(i, a, n) for (int i = a; i <= n; ++i)
#define per(i, a, n) for (int i = n; i >= a; --i)
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 505;
const int inf = 0x3f3f3f3f;
int n, k, dis[maxn], pre[maxn];
int flag[maxn];
struct node{
    
    
    int cnt, step;
};
void bfs() {
    
    
    memset(dis, inf, sizeof(dis));
    memset(pre, -1, sizeof(pre));
    queue<node> q;
    dis[0] = 0; // i面朝上需要的最小步数
    q.push({
    
    0, 0});
    while (q.size()) {
    
    
        node now = q.front();
        q.pop();
        if (dis[now.cnt] < now.step) continue;
        rep(i, 0, k) {
    
    
            if (i > now.cnt || k - i > n - now.cnt) continue;
            int ncnt = now.cnt - i + k - i;
            if (dis[ncnt] > now.step + 1) {
    
    
                dis[ncnt] = now.step + 1;
                q.push({
    
    ncnt, now.step + 1});
                pre[ncnt] = now.cnt;
            }
        }
    }
}
int query(int now, int nex) {
    
    
    vector<int> q, vis(n + 5);
    rep(i, 1, n) {
    
    
        if (q.size() == k) break;
        if (now < nex && flag[i] == 0 || now > nex && flag[i] == 1) {
    
    
            flag[i] ^= 1;
            now += (flag[i] ? 1 : -1);
            q.push_back(i);
            vis[i] = 1;
        }
    }
    int c0 = (k - q.size()) / 2, c1 = c0;
    rep(i, 1, n) {
    
    
        if (vis[i]) continue;
        if (c0 && flag[i] == 0) {
    
    
            flag[i] ^= 1;
            q.push_back(i);
            c0--;
        } else if (c1 && flag[i] == 1) {
    
    
            flag[i] ^= 1;
            q.push_back(i);
            c1--;
        }
    }
    cout << "?";
    for (auto it : q) cout << " " << it;
    cout << endl;
    int ans; cin >> ans; return ans;
}
int main() {
    
    
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> n >> k;
    bfs();
    if (dis[n] == inf) cout << "-1" << endl;
    else {
    
    
        vector<int> cnt;
        for (int i = n; i != -1; i = pre[i])
            cnt.push_back(i);
        reverse(cnt.begin(), cnt.end());
        int ans = 0;
        rep(i, 1, cnt.size() - 1) {
    
    
            ans ^= query(cnt[i - 1], cnt[i]);
        }
        cout << "! " << ans << endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43860866/article/details/118089271