把每个数字按照低位在前高位在后插入到字典树中
那么从低位开始,根节点的左边代表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;