http://acm.hdu.edu.cn/showproblem.php?pid=5269
求所有lowbit(a[i]^b[j])
n∈[1,5∗104]
,
Ai∈[0,229]
其实从后往前找后缀相同的当前不同的对数,因为后缀相同当前位不同,^后后缀变为零,当前位变为1,该位就是权值(2^k)为lowbit值;
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int len;
int a[50010];
const int mod = 998244353;
int f[1500010][3];
int tree[1500010];
int str[36];
int ro,root;
int mark[39]={0};
void insert(int str[],int k)
{
root=0;
int i;
for(i=0;i<k;i++)
{
ro=f[root][str[i]]; //找孩子
if(ro==-1)
{
f[root][str[i]]=len++; //没有孩子 分配空间 放在一维数组 len为待放的位置
f[len-1][0]=-1; //该节点为根节点
f[len-1][1]=-1; //该节点为根节点
ro=len-1;
}
root=ro; //更新父亲节点
tree[root]++;
}
}
int get(int root,int val)
{
int left,right;
int k1,k2;
k1=k2=0;
left=f[root][0];
right=f[root][1];
//printf("!%d %d %d %d\n",left,right,tree[left],tree[right]);
if(left!=-1)
{
k1=get(left,val+1);
}
if(right!=-1)
{
k2=get(right,val+1);
}
if(tree[left]==-1)
tree[left]=0;
if(tree[right]==-1)
tree[right]=0;
return (1LL*((tree[left]%mod)*(tree[right]%mod))%mod*(1LL<<val)%mod+k1+k2)%mod; //注意三个数相乘会超long long
}
int main()
{
int i,j,k,n,m,maxi,ok,pos;
long long s;
int fg=1;
scanf("%d",&n);
while(n--)
{
maxi=-1;
memset(f,-1,sizeof(f));
memset(tree,0,sizeof(tree));
for(i=0;i<=30;i++)
str[i]=0;
tree[0]=0;
len=1;
f[0][0]=-1;
f[0][1]=-1;
scanf("%d",&m);
for(i=0;i<m;i++)
{
scanf("%d",&a[i]);
}
for(i=0;i<m;i++)
{
k=0;
if(a[i]==0)
{
insert(mark,30);
continue;
}
for(j=0;j<=30;j++)
{
str[k++]=(a[i]&(1<<j))?1:0;
}
insert(str,30); //000000..00110 前缀0可能以后会被用到
}
printf("Case #%d: %d\n",fg++,(1LL*2*get(0,0))%mod);
}
}