附 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