附 Bestcoeder 上的题解原文
我们考虑,当A的答案为2^p时,A和B表示成二进制数后末p-1位肯定相同 于是我们维护一颗字母树,将每个数表示成二进制数后翻转可以下,插入字母树 统计答案时,我们找出Ai的二进制数翻转后在字母树上的路径,对于路径上每个点x,设他走的边是v,且当前为第k位,则和他xor后lowbit为2^k的数的个数为trans(x,v^1)的子树大小。 trans(x,v)表示字母树上在结点x,走连出去的字母为v的边到达的结点 时间复杂度:O(nlogA)
。。。。。。蒟蒻想到要建树然而具体不知道。。。。。。
看题解用数组写了一遍TLE了 ⊙_⊙
。。。于是只能第一次用指针建树。。。
#include <iostream>
#include <cstdio>
#include <cstring>
struct tree
{
int cnt;
tree *ch[2];
tree()
{
cnt=0;
memset(ch,0,sizeof(ch));
}
};
const int Mod=998244353;
const int N=50100;
int a[N];
int T,t,n;
void ins(tree *rt,int x)
{
int i;
for (i=0;i<30;i++)
{
int f=x&1;
if (rt->ch[f]==NULL) rt->ch[f]=new tree();
rt=rt->ch[f];
rt->cnt++;
x>>=1;
}
}
long long cal(tree *rt,int x)
{
int i;
int res=0;
for (i=0;i<30;i++)
{
int f=x&1;
tree *op=rt->ch[f^1];
if (op) res=(res+(op->cnt)*(1<<i))%Mod;
rt=rt->ch[f];
x>>=1;
}
return res;
}
int main()
{
scanf("%d",&T);
for (t=1;t<=T;t++)
{
tree *rt=new tree();
scanf("%d",&n);
int i;
for (i=1;i<=n;i++)
{
scanf("%d",&a[i]);
ins(rt,a[i]);
}
long long ans=0;
for (i=1;i<=n;i++)
ans=(ans+cal(rt,a[i]))%Mod;
// empty(rt)懒得写了 不过还是A了。。。
printf("Case #%d: %I64d\n",t,ans);
}
}版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/summonlight/article/details/47830939