字典树 hdu5269 ZYB loves Xor I

把每个数字按照低位在前高位在后插入到字典树中

那么从低位开始,根节点的左边代表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;


你可能感兴趣的:(hdu5269)