题意: 有两种变换:
1. 改变此数二进制的某一位(1变成0 或者 0变成1)
2. 让它与给出的n个数当中的任意一个做异或运算
给你两个数s, t,求从s到t最少要经过几步变换,一共m组查询
思路: 仔细观察会发现其实只与(s^t)有关,那么设x = s^t,那么x就是s和t二进制之间的差别(仔细想想就是s和t相同的位都是0, 不同的都是1,说明只要需要发生变化的位都是1),那么只需要用s^x就得到t了,所以只需要求最少变成x需要多少步,然后再加1就是答案了,那么答案就是从0变成x需要多少步。bfs一下即可。不过还要注意第一个变化条件,在bfs的写出来。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> #define pii pair<int, int> using namespace std; const int maxn = 1e6; const long long mod = 1e9 + 7; int res[maxn]; int a[20]; void bfs(int n) { memset(res, -1, sizeof(res)); res[0] = 0; queue<pii> Q; pii cur, nex; cur.first = cur.second = 0; Q.push(cur); int x = (1 << 17); while (!Q.empty()) { cur = Q.front(); Q.pop(); for (int i = 0; i < n; i++) { nex.first = cur.first ^ a[i]; nex.second = cur.second + 1; if (nex.first < x && res[nex.first] == -1) { res[nex.first] = nex.second; Q.push(nex); } } for (int j = 0; j < 17; j++) { nex.first = cur.first ^ (1 << j); nex.second = cur.second + 1; if (nex.first < x && res[nex.first] == -1) { res[nex.first] = nex.second; Q.push(nex); } } } } int main() { int T, n, m, s, t; scanf("%d", &T); while (T--) { scanf("%d%d", &n, &m); for (int i = 0; i < n; i++) scanf("%d", &a[i]); bfs(n); long long ans = 0; for (int q = 1; q <= m; q++) { scanf("%d%d", &s, &t); t = s ^ t; ans = (ans + (long long)q * res[t]) % mod; } printf("%d\n", (int)ans); } return 0; }