hdu5269 ZYB loves Xor I 异或,字典树
ZYB loves Xor I
Accepts: 142
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
问题描述
ZYB喜欢研究Xor,现在他得到了一个长度为nn的数组A。于是他想知道:对于所有数对(i,j)(i in [1,n],j in [1,n])(i,j)(i∈[1,n],j∈[1,n]),lowbit(A_i xor A_j)lowbit(AixorAj)之和为多少.由于答案可能过大,你需要输出答案对998244353取模后的值
定义lowbit(x)=2^k2k,其中k是最小的满足(xx andand 2^k)>02k)>0的数
特别地:lowbit(0)=0
输入描述
一共TT(T leq 10T≤10)组数据,对于每组数据:
第一行一个正整数nn,表示数组长度
第二行nn个非负整数,第ii个整数为A_{i}Ai
n in [1,5*10^4]n∈[1,5∗104],A_i in [0,2^{29}]Ai∈[0,229]
输出描述
每组数据输出一行Case #x: ans。x表示组数编号,从1开始。ans为所求值。
输入样例
2 5 4 0 2 7 0 5 2 6 5 4 0
输出样例
Case #1: 36 Case #2: 40
之前一直没能过这题,现在看来就很简单了,以后看到异或也自然而然地想到字典树。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) using namespace std; typedef long long ll; const int maxn=1000100; const int INF=(1<<29); const ll MOD=998244353; struct Trie { int ch[2]; int siz; };Trie tr[maxn];int p;int rt; int n,a[maxn]; int newnode() { tr[++p].siz=0; tr[p].ch[0]=tr[p].ch[1]=-1; return p; } void Init() { p=-1; rt=newnode(); } void Insert(int t) { int k=rt; int c=0; tr[k].siz++; REP(i,0,30){ if(t&(1<<i)) c=1; else c=0; if(tr[k].ch[c]==-1) tr[k].ch[c]=newnode(); k=tr[k].ch[c]; tr[k].siz++; } } ll query(int t) { int k=rt; int c; ll res=0; REP(i,0,30){ if(t&(1<<i)) c=1; else c=0; if(~tr[k].ch[c^1]) res+=tr[tr[k].ch[c^1]].siz*(1<<i)%MOD; if(tr[k].ch[c]==-1) break; k=tr[k].ch[c]; } return res%MOD; } int main() { freopen("in.txt","r",stdin); int casen=1; int T;cin>>T; while(T--){ scanf("%d",&n); Init(); REP(i,1,n){ scanf("%d",&a[i]); Insert(a[i]); } ll ans=0; REP(i,1,n) ans+=query(a[i]),ans%=MOD; printf("Case #%d: %I64d ",casen++,ans); } return 0; }