HDU5269 ZYB loves Xor I(分治?解法)

题意:ZYB喜欢研究Xor,现在他得到了一个长度为n的数组A。于是他想知道:对于所有数对(i,j)(i∈[1,n],j∈[1,n]),lowbit(AixorAj)之和为多少.由于答案可能过大,你需要输出答案对998244353取模后的值
定义lowbit(x)=2k,其中k是最小的满足(xand2k)>0的数
特别地:lowbit(0)=0

解法:解法:

先对数组进行排序(先按lowbit后按数大小,从小到大排序)

这样就能按lowbit值不同进行分组。

可以很容易看到两个不同lowbit值的组的数相互xor后的lowbit值为各组lowbit值较小者

那么就可以很快算出某一组与后面比他比他大的数两两xor后的lowbit值(即该组lowbit)的和,【=该组lowbit * 该组长度* 2 * 后面比他大的数的数量】

这里对于0要特判;

然后再加上,递归求解每一组内的两两xor后的lowbit值和,这是个子问题。

对于lowbit相同的组,由于lowbit值相同,那么最后那一位(lowbit位)可以忽略,那么就把该组所有成员都减去该组lowbit,再求解该组即可。。

请忽略代码里注释掉的部分

#include 
#include
#include 
#include
#include
#include
#define LL long long
#define lowbit(x) ((x)&-(x))
#define mod 998244353

using namespace std;
int n,t;
LL arr[50008];
//LL bak[50008];
bool cmp(const LL &a,const LL &b)
{
    LL lba=lowbit(a);
    LL lbb=lowbit(b);
    return  lba==lbb?aint l,int r)
{
    //组内排序 [l,r)
    sort(arr+l,arr+r,cmp);


    if(arr[l]==arr[r-1])//如果组内成员都相同
    {
        return 0;
    }
    LL ans=0;
    int bg=l,ed=l;
    while(bgwhile(ed//找到一个组,[bg,ed)
        LL tmp=0;
        if(arr[bg]==0)//特殊处理
        {

            for(int i=ed;i//用0和后面大于该组的数xor,得出一个0与后面数xor后的lowbit值
            {
                tmp=(tmp+lowbit(arr[i]^0))%mod;
            }
            //该组有多少0, 乘以2是因为要求相互xor
            tmp=tmp*2*(ed-bg)%mod;

        }
        else
        {
            //该组长度*后边长度*2*该组lowbit
            tmp=val*2*(r-ed);
            tmp%=mod;
            tmp=tmp*(ed-bg)%mod;

        }

        ans=(ans+tmp)%mod;

        for(int i=bg;i//分治求解
        ans=(ans+solve(bg,ed))%mod;
        //计算下一段
        bg=ed;
    }

    return ans%mod;
}
/*
//暴力解法,注意我的解法会破坏arr,请务必保证solve2在solve前
LL solve2()
{
    LL ret=0;
    for(int i=0;i
int main()
{
     srand(time(NULL));
    cin>>t;
    for(int ncase=1;ncase<=t;ncase++)
    {
        cin>>n;
        for(int i=0;icin>>arr[i];
        LL ans=solve(0,n);
        cout<<"Case #"<": "<return 0;
}

你可能感兴趣的:(ACM-分治)