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
",++cas,work(nums)*2);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Cw-trip/p/4574194.html