又是一道字典树,,
题目大意
给你了n个数,然后让你求对于所有的i和j,lowbit(a[i]异或a[j])之和。
思路
如果要是学过树状数组,应该对lowbit()不陌生了,lowbit(x)它就是求x二进制下的最低一位不为0的数,比如lowbit(4)=2;lowbit(5)=1;lowbit(16)=8;
异或就不用说了,lowbit(a[i]异或a[j]),就是比较a[i]和a[j]二进制下从后往前的相同的位数,那么我们就可以建一个字典树(二进制从后往前建树),记录每个节点的个数。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
const int N=50000+10;
int s[N];
struct zxc
{
int num;
int a[2];
}tree[35*N];
int numm;
long long ans=0;
int mod=998244353;
int n;
void init(int x)
{
tree[x].num=0;
tree[x].a[0]=-1;
tree[x].a[1]=-1;
}
void bulid(int x)
{
int u=0;
int c;
for(int i=0;i<30;i++,x/=2)
{
c=x&1;
if(tree[u].a[c]==-1)
{
tree[u].a[c]=numm++;
u=tree[u].a[c];
init(u);
}
else
{
u=tree[u].a[c];
}
tree[u].num++;
}
}
long long fin(int x)
{
int u=0;
long long tot=0;
int q=1;
int c;
for(int i=0;i<30;i++,q*=2,x/=2)
{
c=x&1;
tot=(tot+tree[tree[u].a[c^1]].num*q%mod)%mod;
u=tree[u].a[c];
}
return tot;
}
int main()
{
int t;
int w=1;
scanf("%d",&t);
while(t--)
{
init(0);
numm=1;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&s[i]);
bulid(s[i]);
}
ans=0;
for(int i=1;i<=n;i++)
{
ans+=fin(s[i]);
ans%=mod;
}
printf("Case #%d: %lld\n",w++,ans);
}
return 0;
}