hdu 5269 ZYB loves Xor I(计数

题意:给出n个数,n个数两两异或后的最后一个bit位k,求所有2^k的和。

比赛的时候递归写挂了。。。。痛心啊。。。后来看了半天结果把一个数组移到函数体里就1a了(递归的时候覆盖了。。。)T_T。

思路是这样的:如果最后一位不相同,那么他们异或结果的最后一位与二者最后一位较低的相同,那么把这些数字按最后一位的位置分为若干组,然后不同组可以直接相乘。相同组因为最后一位相同,所以异或的结果与最后一位无关,把最后一位去掉然后递归处理这一组。因为一共有30位,数组长度为n,复杂度大概是O(30*n)。

#include<iostream>

#include<map>

#include<algorithm>

#include<cstdio>

#include<cstring>

#include<cstdlib>

#include<vector>

#include<queue>

#include<stack>

#include<functional>

#define pb push_back

using namespace std;

typedef long long ll;

const int maxv=5e4+40;

const ll mod=998244353;

int T,cas=0;

ll a[maxv];

int n;

vector<ll> nums;

ll work(vector<ll> b){

    vector<ll> bucket[32];

    bool flag=0;

    for(int i=0;i<b.size();i++){

        int p;

        if(b[i]){

            p=__builtin_ffs(b[i])-1;

            flag=1;

        }

        else p=31;

        bucket[p].pb(b[i]);

    }

    if(!flag) return 0;

    ll ans=0;

    for(int i=0;i<32;i++){

        for(int j=i+1;j<32;j++){

            if(bucket[i].size()&&bucket[j].size()){

                ans=(ans+(1ll<<(i))*bucket[i].size()%mod*bucket[j].size()%mod)%mod;

            }

        }

    }

    for(int i=0;i<31;i++){

        if(bucket[i].size()){

            for(int j=0;j<bucket[i].size();j++){

                int p=__builtin_ffs(bucket[i][j])-1;

                bucket[i][j]^=1ll<<p;

            }

            ans=(work(bucket[i])+ans)%mod;

        }

    }

    return ans;

}

int main(){

    cin>>T;

    while(T--){

        cin>>n;

        nums.clear();

        for(int i=0;i<n;i++) scanf("%lld",&a[i]);

        for(int i=0;i<n;i++) nums.pb(a[i]);

        printf("Case #%d: %lld\n",++cas,work(nums)*2);

    }

    return 0;

}
View Code

 

你可能感兴趣的:(love)