题意:
对一个数,给定两种操作:
1. 把这个数的某个二进制位翻转
2. 把这个数和给定的n个数中的某一个数进行异或
问把 x 转化为y 最少需要多少步?( n≤15,x,y≤105 )
解释:
注意到异或的一个性质,题目就转化为求怎样经过最少的步数转换得到 x ^ y,数只有 100000 ,所以预处理搜一波就行了!
还有就是翻转某一位就等价于和 (1<<i) 进行异或。
代码:
#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
int d[300000],n,m,x[20];
queue<int> Q;
const int mo = 1e9+7;
void firget()
{
memset(d,0xff,sizeof d);
d[0]=0;
Q.push(0);
while (!Q.empty())
{
int k1 = Q.front(); Q.pop();
for (int i = 0;i <= 16;i ++){
int k2 = (k1 ^ (1<<i));
if (d[k2] == -1){
d[k2] = d[k1] + 1; Q.push(k2);
}
}
for (int i = 1;i <= n;i ++){
int k2 = (k1 ^ x[i]);
if (d[k2] == -1){
d[k2] = d[k1] + 1; Q.push(k2);
}
}
}
}
int main()
{
int t; scanf("%d",&t);
while(t --)
{
scanf("%d%d", &n, &m);
for (int i = 1;i <= n;i ++) scanf("%d",&x[i]);
firget();
int ans = 0, now = 0;
while(m --){
now ++;
int s,t;
scanf("%d%d", &s, &t);
ans = (ans + 1ll * now * d[s^t]) % mo;
}
printf("%d\n",ans);
}
return 0;
}