HDU 5269 ZYB loves Xor I 贡献+Trie

来源:互联网 发布:mac 邮件归类 编辑:程序博客网 时间:2024/06/08 19:15
HDU 5269
题意:给出序列a,求累加和:lowbit(a[i] xor a[j]) [i=1..n,j=1..n] n,a[i]<=2^30
lowbit(x)=1<<pos.  pos为:x二进制中最右边一个1的位置


010
110 异或结果为100.
枚举a[i]二进制中起作用的1,则与a[i]异或的x,要满足a[i]和x的后缀pos(第pos位相反)是相同.用map记录后缀出现次数,O(30*n*logn) TLE.
每个a[i]倒着插入Trie中,若下一位为1 则统计下一位为0时的后缀有多少个即可.O(30*n).


另一种方法是分治,先算不同位是第一位的 则会把序列a分成两个集合.

接着算不同位为第二位的 则在这两个集合里面分别计算,接着递归下去即可.

#include <bits/stdc++.h>using namespace std;typedef long long ll;const int N=5e4+5,M=35,mod=998244353;int ch[N*32][2],cnt[N*32],sz,a[N];ll ans;void init(){    memset(ch[0],0,sizeof(ch[0]));    memset(cnt,0,sizeof(cnt));    sz=1;    ans=0;}void insert(int x){    int u=0;    for(int i=0;i<30;i++)    {        int c=(x>>i)&1;        if(!ch[u][c])        {            memset(ch[sz],0,sizeof(ch[sz]));            ch[u][c]=sz++;        }        u=ch[u][c];        cnt[u]++;    }}void query(int x){    int u=0;    for(int i=0;i<30;i++)    {        int c=(x>>i)&1;        int num=cnt[ch[u][c^1]];        if(c)        {            ans=(ans+(1ll<<i)*num)%mod;          //  cout<<x<<' '<<i<<' '<<num<<endl;        }        u=ch[u][c];    }}int main(){    int T,n,x,cas=0;    scanf("%d",&T);    while(T--)    {        init();        scanf("%d",&n);        for(int i=1;i<=n;i++)        {            scanf("%d",&a[i]);            insert(a[i]);        }        for(int i=1;i<=n;i++)            query(a[i]);        ans=(ans*2ll)%mod;        printf("Case #%d: %lld\n",++cas,ans);    }    return 0;}


原创粉丝点击