题意:
T组样例,给你n个数。你要找出来这n个数中任意两个数的二进制位中 最低位不同 的位置(假设是k),然后让所有2^k加起来就是结果
什么意思?
例如4 和 2
4的二进制是(100),2的二进制是(010),那么它们二进制位中 最低位不同 的位置 就是1,然后把这个2^1加入最后结果就完了
注意:4和2算一次结果,2和4也要算一次结果
解释个样例:
5
4 0 2 7 0
sum=0
4和0:k=2,sum+=2^2
4和2:k=1,sum+=2^1
4和7:k=0,sum+=2^0
4和0:k=2,sum+=2^2
0和2:k=1,sum+=2^1
0和7:k=0,sum+=2^0
0和0:因为0^0=0,题目上lowbit(0)=0,所以sum+=0
2和7:k=0,sum+=2^0
2和0:k=1,sum+=2^1
7和0:k=0,sum+=2^0
sum=4+2+1+4+2+1+0+1+2+1=18
又因为“4和2算一次结果,2和4也要算一次结果”,所以sum*=2
sum=36
题解:
观察发现对于任意一个数 x 来说,只要前 i-1 位和其它数相等,第i位不相等。那么 ans += cnt * pow(2, i-1);
cnt 为和它前i-1个前缀都相等的数的个数。 可以利用字典树边插入边更新ans,最后ans*2就是答案。
数组开小了TLE了半天。。。。
代码:
1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 #include <cstdlib>
5 #include <algorithm>
6 using namespace std;
7 typedef long long ll;
8 const int maxn=2;
9 const ll mod=998244353;
10 typedef struct Trie* TrieNode;
11 ll v[50005];
12 ll w[31],result;
13 struct Trie
14 {
15 ll val,sum;
16 TrieNode next[2];
17 Trie()
18 {
19 val=0;
20 sum=0;
21 memset(next,NULL,sizeof(next));
22 }
23 };
24
25 void inserts(TrieNode root,ll x,ll y)
26 {
27 TrieNode p = root;
28 for(ll i=0;i<30;++i)
29 {
30 ll temp=(x>>i)&1;
31 if(p->next[temp]==NULL) p->next[temp]=new struct Trie();
32 if(p->next[!temp]!=NULL && p->next[!temp]->sum>0)
33 {
34 ll t=p->next[!temp]->sum;
35 t=(t*(ll)w[i])%mod;
36 result=(result+t)%mod;
37 }
38 p->next[temp]->sum+=y;
39 p=p->next[temp];
40 }
41 p->val=x;
42 }
43 void Del(TrieNode root)
44 {
45 for(ll i=0 ; i<2 ; ++i)
46 {
47 if(root->next[i])Del(root->next[i]);
48 }
49 delete(root);
50 }
51
52 int main()
53 {
54 ll t,n,sum=1;
55 int p=0;
56 w[0]=1;
57 for(int i=1;i<=30;++i)
58 {
59 sum=(sum*2)%mod;
60 w[i]=sum;
61 }
62 scanf("%lld",&t);
63 while(t--)
64 {
65 TrieNode root = new struct Trie();
66 scanf("%lld",&n);
67 //ll ans=0;
68 result=0;
69 for(ll i=1;i<=n;++i)
70 {
71 scanf("%lld",&v[i]);
72 inserts(root,v[i],1);
73 }
74 printf("Case #%d: %lld\n",++p,(result<<1)%mod);
75 Del(root);
76 }
77 return 0;
78 }