ZYB loves Xor I (HDU-5269)(字典树)

Memphis loves xor very musch.Now he gets an array A.The length of A is n.Now he wants to know the sum of all (lowbit(AiAi xor AjAj)) (i,j∈[1,n])(i,j∈[1,n])
We define that lowbit(x)=2k2k,k is the smallest integer satisfied ((xx and 2k2k)>0)
Specially,lowbit(0)=0
Because the ans may be too big.You just need to output ansans mod 998244353

Input

Multiple test cases, the first line contains an integer T(no more than 10), indicating the number of cases. Each test case contains two lines
The first line has an integer nn
The second line has nn integers A1A1,A2A2....AnAn
n∈[1,5∗104]n∈[1,5∗104],Ai∈[0,229]Ai∈[0,229]

Output

For each case, the output should occupies exactly one line. The output format is Case #x: ans, here x is the data number begins at 1.

Sample Input

2
5
4 0 2 7 0
5
2 6 5 4 0

Sample Output

Case #1: 36
Case #2: 40

题意:给你一个序列[a, a + n),求所有lowbit(Ai xor Aj)的和。即Ai^Aj的值第一个1出现的位置k,求k<<1的和。
思路:这道题的话,因为异或运算相同为0,不同为1。lowbit函数是找一个数表示成2进制数,从最低位开始第一个不为0的数之前有k个0,则结果为2^k。比如2,4。 2:010  4:100   我们发现(右数,最右边为第0位)从第0位开始起,他们第1位不同,所以我们可以判断第1位之前都为0,那么lowbit值为2^1。所以我们可以建立一个字典树,每输入一个数对其做一次计算,加上之前的和他不同的个数,因为是没有顺序的,最后结果乘以2。

AC代码:

#include <bits/stdc++.h>
typedef long long ll;
const int maxx=50010;
const int maxn=2;
const int inf=0x3f3f3f3f;
const int mod=998244353;
using namespace std;
int Trie[30*maxx][maxn];
int num[30*maxx];
int color[110];
int a[maxx];
int k;
ll ans;
void init()
{
    memset(Trie,0,sizeof(Trie));
    memset(num,0,sizeof(num));
    k=0;
}
int newnode()
{
    num[++k]=0;
    Trie[k][0]=Trie[k][1]=0;
    return k;
}
void insert(ll w)
{
    int p=0;
    for(int i=0; i<30; i++)
    {

        int c=(w>>i)&1;
        if(Trie[p][c])
        {
            ans+=color[i]*num[Trie[p][c^1]];
            ans%=mod;
        }
        else
        {
            Trie[p][c]=newnode();
            Trie[p][c^1]=newnode();
        }
        p=Trie[p][c];
        num[p]++;
    }
}
int main()
{
    color[0]=1;
    for(int i=1; i<=30; i++)
        color[i]=2*color[i-1];
    int t;
    scanf("%d",&t);
    int cas=1;
    while(t--)
    {
        init();
        int n;
        scanf("%d",&n);
        ans=0;
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
            insert(a[i]);
        }
        ans=ans*2%mod;
        printf("Case #%d: %lld\n",cas++,ans);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值