把每个数字按照低位在前高位在后插入到字典树中
那么从低位开始,根节点的左边代表0,右边代表1,如果左右两边都有,那么就是左边的数量*右边的数量*F[cnt]
然后对左边和右边分治就可以得到答案了
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<queue> #include<vector> #include<algorithm> using namespace std; typedef long long LL; const int MX=50000+5; const LL mod=998244353; LL F[MX]; struct Trie{ int sum; Trie *Nxt[2]; Trie(){ sum=0; Nxt[0]=Nxt[1]=NULL; } }; void Trie_add(Trie*root,int x){ for(int i=0;i<=31;i++){ int w=((x&(1<<i))!=0); if(root->Nxt[w]==NULL){ root->Nxt[w]=new Trie(); } root=root->Nxt[w]; root->sum++; } } void init(){ for(int i=0;i<=31;i++){ F[i]=1LL<<i; } } LL solve(Trie*root,int cnt){ LL ret=0,l,r; if(root->Nxt[0]==NULL) l=0; else{ l=root->Nxt[0]->sum; ret=(ret+solve(root->Nxt[0],cnt+1))%mod; } if(root->Nxt[1]==NULL) r=0; else{ r=root->Nxt[1]->sum; ret=(ret+solve(root->Nxt[1],cnt+1))%mod; } ret+=l*r*F[cnt]%mod; return ret; } int main(){ int T,n,t,ansk=0; scanf("%d",&T); init(); while(T--){ scanf("%d",&n); Trie *root=new Trie(); for(int i=1;i<=n;i++){ scanf("%d",&t); Trie_add(root,t); } printf("Case #%d: %I64d\n",++ansk,solve(root,0)*2%mod); } return 0;