HDOJ 5639 Transform

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5637

题意:有一个数x,你可以对x进行两种操作,1.反转x二进制其中任意一位2.x^y(y题目给出), 有n个数可以用来当y,有m组询问,每组询问两个数s,t,求

 S=(izi) 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 }
原文地址:https://www.cnblogs.com/as3asddd/p/6087600.html