本文最后更新于:2022年5月21日 下午
E: Lost Array
题目翻译
给你 n 个数,分别是a1,a2,a3,⋯,an,目的是计算这 n 个数的异或的值。你可以通过询问 k 个数的方式,来获得任意 k 个数的异或值。
- 如果无法求得 n 个数的异或值,输出
-1
。
- 如果可以求得 n 个数的异或值,需要使用最少的询问次数。输出 n 个数的异或值。
数据范围:n∈[1,500],k∈[1,n],ai∈[1,109]。
题目思路
首先判断是否能求得这 n 个数的异或值,如果能够求得,就计算出询问次数。
这里抽象一下题意,理解为一个位置移动问题。刚开始在座标轴起点 0, 每次可以向左或者右移动共 k 位,但是不能走到比 0 小的位置,也不能走到大于 n 的位置,问能不能到达 n 。位置移动的所在位置相当于当前已经询问之后的异或的数的值。移动中向左移动 Lk 位,向右边移动 Rk 位,Lk+Rk=k,这相当于取的 k 个数中,有 Lk 个数是之前选择过的,异或之后需要将它移出,有 Rk 个数是之前没有选择过的,异或之后,需要将他们添加到选择的列表中。这样的问题,可以用BFS解决。每次移动可以向左移动 i(0≤i≤k),那么就会向右移动 k−i 位。如果发现到不了 n,就表示到不了目的地。
参考代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| #include <bits/stdc++.h>
using namespace std; int n, k;
int dis[555]; int method[555]; int prev1[555]; const int inf = 0x3f3f3f3f; int main() { ios::sync_with_stdio(false); cin.tie(0); cin >> n >> k; queue<int> Q; Q.push(0); memset(prev1, 0x3f, sizeof prev1); memset(dis, 0x3f, sizeof dis); dis[0] = 0; prev1[0] = -1; while (!Q.empty()) { auto x = Q.front(); Q.pop(); for (int i = 0; i <= k; ++i) { if (i + x <= n and k - i <= x) { int nex = x + i - (k - i); if (dis[nex] == inf) { prev1[nex] = x; method[nex] = i; dis[nex] = dis[x] + 1; Q.push(nex); } } } } if (dis[n] == inf) { cout << -1 << endl; } else { vector<int> path; vector<int> select, unselect; for (int i = n; i != -1; i = prev1[i]) { path.push_back(i); } reverse(path.begin(), path.end()); for(int i = 0; i < n; ++i){ unselect.push_back(i + 1); } int ret = 0; for (int i = 1; i < path.size(); ++i) { int nosel = method[path[i]]; int sel = k - method[path[i]];
vector<int> tselect, tunselect; for (int i = 0; i < nosel; ++i) { tunselect.push_back(unselect.back()); unselect.pop_back(); } for (int i = 0; i < sel; ++i) { tselect.push_back(select.back()); select.pop_back(); } cout << "?"; for (auto it : tselect) { cout << " " << it; } for (auto it : tunselect) { cout << " " << it; } cout << endl; cout.flush(); select.insert(select.end(), tunselect.begin(), tunselect.end()); unselect.insert(unselect.end(), tselect.begin(), tselect.end()); int tmp; cin >> tmp; ret ^= tmp; } cout << "! " << ret << endl; } return 0; }
|