【HDU】5269 ZYB loves Xor I

【算法】trie

【题解】

为了让数据有序,求lowbit无法直接排序,从而考虑倒过来排序,然后数据就会呈现出明显的规律:

法一:将数字倒着贴在字典树上,则容易发现两数的lowbit就是它们岔道结点的深度,所以先建树后对于一个数字依次把每次分岔开的另一边的size乘上权值累加答案。

法二:从高位到低位分组求和,即第一位1在上,0在下,则两边之间互相计算过后就再无影响,只剩下各自内部的事情再处理。由于排序后数据的有序性使分治可行。

法三:排序后对于一个数字,它和后面的数字的lowbit有单调性……然后可以维护它,相当麻烦,不再赘述。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=50010,MOD=998244353;

int size[maxn*50],t[maxn*50][2],tot,a[maxn],n;
void insert(int x,int dep,int num)
{
    if(dep>30)return;
    if(t[x][num&1])
    {
        size[t[x][num&1]]++;
    }
    else 
    {
        t[x][num&1]=++tot;
        t[t[x][num&1]][0]=t[t[x][num&1]][1]=0;
        size[t[x][num&1]]=1;
    }
    insert(t[x][num&1],dep+1,num>>1);
}
int query(int x,int dep,int num)
{
    if(dep>30)return 0;
    long long ansnow=((t[x][(num&1)^1]?size[t[x][(num&1)^1]]:0)<<dep)%MOD;
    if(t[x][(num&1)])ansnow=((ansnow+query(t[x][num&1],dep+1,num>>1)))%MOD;
    return (int)(ansnow%MOD);
}
int main()
{
    int T,now=0;
    scanf("%d",&T);
    long long ans=0;
    while(T--)
    {
        now++;
        tot=1;
        t[1][0]=t[1][1]=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            insert(1,0,a[i]);
        }
        ans=0;
        for(int i=1;i<=n;i++)ans=(ans+query(1,0,a[i]))%MOD;
        printf("Case #%d: %d
",now,(int)(ans%MOD));
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/onioncyc/p/7082174.html