转化一下,可以理解为用n个数异或,和修改位,去凑出s异或t的值。我们可以先用dfs计算n个数互相异或能得到哪些数,并且最少需要其中的多少个数来异或(也就是需要多少次操作),然后推出范围内的数通过异或和反转位,最少需要多少步。不过更科学的方法应该是用bfs求这些最短距离(最少操作次数)。对于询问O(1)查表回答即可。
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <string>
#include <memory.h>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
#define ll long long
const ll mod = 1e9+7;
int a[20];
int tab[131072+10];
int N,m;
void dfs(int n,int k,int cur){
if(n>N)return;
if(tab[cur^a[n]]+1<tab[cur]){
tab[cur] = tab[cur^a[n]]+1;
}
dfs(n+1,k,cur);
dfs(n+1,k+1,cur^a[n+1]);
}
int main(){
int t;
cin>>t;
while(t--){
for(int i=0;i<131072;i++){
tab[i]=1000000000;
}
tab[0]=0;
cin>>N>>m;
for(int i=1;i<=N;i++){
cin>>a[i];
}
dfs(0,0,0);
for(int i=131072-1;i>0;i--){
int tmp=1;
while(tmp<131072){
if(i&tmp){
if(tab[i] > tab[i-tmp]+1){
tab[i] = tab[i-tmp]+1;
}
}else{
if(tab[i] > tab[i+tmp]+1){
tab[i] = tab[i+tmp]+1;
}
}
tmp<<=1;
}
}
for(int i=1;i<131072;i++){
int tmp=1;
while(tmp<131072){
if(i&tmp){
if(tab[i] > tab[i-tmp]+1){
tab[i] = tab[i-tmp]+1;
}
}else{
if(tab[i] > tab[i+tmp]+1){
tab[i] = tab[i+tmp]+1;
}
}
tmp<<=1;
}
}
ll ans = 0;
for(int i=1;i<=m;i++){
int s,t;
scanf("%d%d",&s,&t);
ll cur = tab[s^t];
cur*=i;
ans+=cur;
ans%=mod;
}
cout<<ans<<endl;
}
return 0;
}
本文探讨了使用深度优先搜索(DFS)和位操作来解决计算通过异或和反转位最少需要多少步骤的问题。通过预计算得到的位集和最少操作次数表,实现快速查询。
359

被折叠的 条评论
为什么被折叠?



