题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5637
题意:有一个数x,你可以对x进行两种操作,1.反转x二进制其中任意一位2.x^y(y题目给出), 有n个数可以用来当y,有m组询问,每组询问两个数s,t,求
S=(∑i⋅zi) mod (1e9+7),其中zi是在第i次询问,通过两种操作把s变成t所需要的最小操作次数;
思路:s,t最大只有1e5相当于2^16左右,假设s^n1^n2^...^nk=t,那么转换到n1^n2^...^nk=s^t,也就是最小步数跟这两个数的异或值有关,那么预处理出所有1e5以内的异或值并且做到这个值所需要的最小步数,然后直接查询
1 #include <stdio.h> 2 #include <iostream> 3 #include <string.h> 4 #include <algorithm> 5 #include <queue> 6 #include <cstdlib> 7 using namespace std; 8 #define P pair<int,int> 9 const int mod=1e9+7; 10 int a[20]; 11 int ans[1<<20]; 12 bool flag[1<<20]; 13 int n,m; 14 void bfs(){ 15 queue<pair<int,int> >q; 16 q.push(make_pair(0,0)); 17 memset(flag,false,sizeof(flag)); 18 flag[0]=true; 19 while(!q.empty()){ 20 P tmp=q.front(); 21 q.pop(); 22 int x=tmp.first; 23 ans[x]=tmp.second; 24 for(int i=1;i<=n;i++){ 25 if(!flag[tmp.first^a[i]]){ 26 q.push(make_pair(tmp.first^a[i],tmp.second+1)); 27 flag[tmp.first^a[i]]=true; 28 } 29 } 30 for(int i=0;i<=17;i++){ 31 if(!flag[tmp.first^(1<<i)]){ 32 flag[tmp.first^(1<<i)]=true; 33 q.push(make_pair(tmp.first^(1<<i),tmp.second+1)); 34 } 35 } 36 } 37 } 38 void pre(){ 39 memset(ans,0,sizeof(ans)); 40 bfs(); 41 } 42 void solve(){ 43 long long ans_=0; 44 scanf("%d %d",&n,&m); 45 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 46 pre(); 47 for(int i=1;i<=m;i++){ 48 int s,t; 49 scanf("%d %d",&s,&t); 50 (ans_+=(i*ans[s^t]))%=mod; 51 } 52 printf("%lld ",ans_); 53 } 54 int main(){ 55 int T; 56 scanf("%d",&T); 57 while(T--){ 58 solve(); 59 } 60 return 0; 61 }