HDU 5269 ZYB loves Xor I Trie树

题目链接:

hdu:http://acm.hdu.edu.cn/showproblem.php?pid=5269

bc:http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=603&pid=1002

题解:

  (以下有提到位数的都是指二进制表示)

  对于xor值为1的两个数,他们的最低位(二进制表示)必然不同,所以我们把n个数按最低位数不同分为两堆,这两堆个数的乘积就是xor的值等于1的贡献。同理,我们可以递归处理出xor值等于2,4,8,16...2^30的贡献值,然后把它们加起来。

  一种做法是类似快速排序先按最低位数排序,0的在左边,1的在右边,算完2^0的贡献之后,再递归算全0的那块,全1的那块中2^1的贡献,依次类推。不过这种做法的缺陷是最坏情况下时间复杂度会变为n^2;

  一种高效的做法是用一颗trie树来维护,把每个数从最低位开始按每一位的01取值存到trie树上,这样某一位为零的都会在左子树上,为1的都会在右子树上。这样离线处理好就不用我们每一次递归的时候去维护了.

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring> 
 4 using namespace std;
 5 
 6 const int maxn=50000+10;
 7 const int mod=998244353;
 8 typedef long long LL;
 9 
10 struct Trie{
11     int ch[maxn*33][2],tot;
12     int val[maxn*33];
13     void init(){
14         val[0]=0;
15         memset(val,0,sizeof(val));
16         memset(ch[0],0,sizeof(ch[0]));
17         tot=1;
18     }
19     void insert(int x){
20         int p=0;
21         for(int i=0;i<30;i++){
22             int tmp;
23             if((1<<i)&x) tmp=1;
24             else tmp=0;
25             if(!ch[p][tmp]){
26                 memset(ch[tot],0,sizeof(ch[tot]));
27                 ch[p][tmp]=tot++;
28             }
29             p=ch[p][tmp];
30             val[p]++;
31         }
32     }
33     void query(int cur,int h,LL &ans){
34         int lef=ch[cur][0],rig=ch[cur][1];
35         LL tmp=(LL)val[lef]*val[rig]%mod*(1<<h)%mod;
36 //        printf("tmp:%d\n",tmp);
37         ans+=tmp;
38         ans%=mod;
39         if(lef) query(lef,h+1,ans);
40         if(rig) query(rig,h+1,ans);
41     }
42 }trie;
43 
44 int n;
45 
46 void init(){
47     trie.init();
48 }
49 
50 int main(){
51     int tc,kase=0;
52     scanf("%d",&tc);
53     while(tc--){
54         init();
55         scanf("%d",&n);
56         for(int i=0;i<n;i++){
57             int x;
58             scanf("%d",&x);
59             trie.insert(x);
60         }
61 //        for(int i=0;i<22;i++) printf("val:%d\n",trie.val[i]); 
62         LL ans=0;
63         trie.query(0,0,ans);
64         printf("Case #%d: %lld\n",++kase,ans*2%mod);
65     }
66     return 0;
67 }
posted @ 2016-04-11 15:42  fenicnn  阅读(207)  评论(0编辑  收藏  举报