zoukankan      html  css  js  c++  java
  • 2019牛客暑期多校训练营(第一场)H XOR(线性基)

    题意:给你n个数字,然后让你求所有满足异或和为0的子集的大小之和。

    先对n个数求线性基,设线性基大小为r,可以分别计算线性基内数的贡献和线性基外数的贡献

    1.线性基外:共n-r个数,枚举每个数x,将线性基外剩余的n-r-1个数任意排列,显然共有 2^(nr1)个集合,这些集合再异或x的结果还是能被线性基异或出,所以x的贡献为 2^(nr1)。

    2.线性基内:枚举每个数x,将所有剩余的n-1个数再求一次线性基,设为B,分两种情况:

    (1) x能被插入线性基。那么显然x不能在任意一个集合中出现,x的贡献为0。

    (2) x不能被插入线性基。此时B的大小必定也为r,因为B已经能表示所有n个数了。那么在除去x和B的情况下,剩余n-r-1个数显然也是任意排列,x贡献为 2^(nr1)

    #include<bits/stdc++.h>
    #define ll long long
    const int inf = 0x3f3f3f3f;
    const int N = 1e5+7;
    const ll mod = 1e9+7;
    using namespace std;
    struct Linear_basis{
        int cnt;
        ll b[65];
        void init(){
            cnt=0;
            memset(b,0,sizeof(b));
        }
        bool insert(ll x){
            for(int i=63;i>=0;i--){
                if(x&(1LL<<i)){
                    if(!b[i]){
                        b[i]=x; cnt++;
                        return 1;
                    }
                    x^=b[i];
                }
            }
            return 0;
        }
    };
    Linear_basis x,y,z;
    ll q_pow(ll a,ll n){
        ll ans=1; ll base=a;
        while(n){
            if(n&1) ans=(ans*base)%mod;
            base=(base*base)%mod;
            n>>=1;
        }
        return ans;
    }
    ll a[N];
    vector<ll> v,v1;
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        int n;
        while(cin>>n){
            x.init(); y.init(); z.init();
            v.clear(); v1.clear();
            for(int i=1;i<=n;i++) cin>>a[i];
            for(int i=1;i<=n;i++){
                if(!x.insert(a[i])){
                    v.push_back(a[i]);
                }else v1.push_back(a[i]);
            }
            ll sum=0;
            sum=(sum%mod+((n-x.cnt)*q_pow(2,n-x.cnt-1))%mod)%mod;
            for(int i=0;i<v.size();i++){
                y.insert(v[i]);
            }
            for(int i=0;i<v1.size();i++){
                z=y;
                for(int j=0;j<v1.size();j++){
                    if(i==j) continue;
                    z.insert(v1[j]);        
                }
                if(!z.insert(v1[i])){
                    sum=(sum+q_pow(2,n-z.cnt-1))%mod;    
                }
            }
            cout<<sum<<endl;
        }
        return 0;
    }
  • 相关阅读:
    JQuery中$.ajax()方法参数详解
    overload和override的区别
    linux 安装jdk和tomcat
    linux链接外网手动设置
    RISC与CISCCPU构架
    32位与64位内存区别
    system 系统调用、gcc编译过程
    c helloworld
    C语言中 有符号数、无符号数、整数溢出 (转)
    samba安装
  • 原文地址:https://www.cnblogs.com/wmj6/p/11231926.html
Copyright © 2011-2022 走看看