zoukankan      html  css  js  c++  java
  • 2019牛客多校第一场H XOR 线性基模板

    H XOR

    题意

    给出一组数,求所有满足异或和为0的子集的长度和

    分析

    n为1e5,所以枚举子集肯定是不可行的,这种时候我们通常要转化成求每一个数的贡献,对于一组数异或和为0.我们考虑使用线性基,对这一组数求线性基,设基的长度为r,由线性代数的知识我们可以知道,在这个数组中取一个数,这个线性基有唯一一种组成方式使得异或这个数为0。所以对于不在线性基的每一个数,他可以组成的子集个数为(2^{n-r-1}),所以所有不构成线性基的数的贡献为((n-r)*2^{n-r-1}),那么对于在线性基里的数怎么办呢?,这就转化成了用剩下的n-1个数能不能表示出这个数,有多少种表示这个数的方式,我们可以对剩下的n-r的数再求一次基,如何才能表示出这个数呢,由线性定理只是可以知道,同一个组数的线性基可以不同,但他们秩是相同的,而要表示的这个数在一个线性基里面,所以要表示他,我们对于剩下的数,如果秩还是r,就可以表示,那么这个数就可以和n-1-r个数组成子集贡献就是(2^{n-r-1}),否则贡献就是0了

    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include<vector>
    #include<iostream>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    typedef  long long  UI;
    const int maxn=1e5+9;
    int vis[maxn];
    UI a[maxn];
    const int mod=1e9+7;
    ll mul(ll a,ll b){
        return a%mod*b%mod;
    }
    ll fpow(ll a,ll b){
        ll ans=1;
        while(b){
            if(b&1)ans=mul(ans,a);
            b>>=1;
            a=mul(a,a);
        }
        return ans;
    }
    #define weishu 62
    UI x[weishu+1];
    struct LinearBasis{
        UI basis[weishu+1];//32位
        int num;
        int cnt;//极大无关组大小
        void clear(){ memset(basis,0,sizeof(basis)); num=0;cnt=0; }//清零
        void insert(UI x){ basis[num++]=x; }//单纯存数组,没有插入线性基
        bool d_insert(UI x){//直接插入线性基
            bool flag=0;
               for(int j=weishu;j>=0;j--)
                if ((x>>j)&1) {
                    if (basis[j]==0) {
                        cnt++;
                        basis[j]=x;
                        return 1;
                    }
                    else {
                        x^=basis[j];
                    }
            }
               return 0;
        }
        void build(){//用数组里面存的数生成线性基
            cnt=0;
            num--;
            for(int i=0;i<=num;i++) x[i]=basis[i];
            memset(basis,0,sizeof(basis));
           for(int i=0;i<=num;i++)  {
               for(int j=weishu;j>=0;j--)
                if ((x[i]>>j)&1) {
                    if (basis[j]==0) {
                        cnt++;
                        basis[j]=x[i];
                        break;
                    }
                    else {
                        x[i]^=basis[j];
                    }
                }
            }
            num=0;
        }
        int check(UI x){//判断一个数在不在线性基中
           for(int i=weishu;i>=0;i--)
            if ((x>>i)&1) {
                if (basis[i]==0) break;
                else x^=basis[i];
            }
            return (x==0);
        }
    }bs,bs2;
    vector<int>v;
    int main(){
        int n;
        while(scanf("%d",&n)==1){
            v.clear();
            bs.clear(),bs2.clear();
            for(int i=1;i<=n;i++){
                vis[i]=0;
                scanf("%lld",&a[i]);
            }
            for(int i=1;i<=n;i++){
                if(bs.d_insert(a[i])){
                    v.push_back(i);
                    vis[i]=1;
                }
            }
            ll r=bs.cnt;
            ll ans=mul(n-bs.cnt,fpow(2,n-bs.cnt-1));
            for(int i=1;i<=n;i++){
                if(vis[i]==0){
                        bs2.d_insert(a[i]);
                }
            }
            for(int i=0;i<v.size();i++){
                bs=bs2;
                for(int j=0;j<v.size();j++){
                    if(i!=j){
                        bs.d_insert(a[v[j]]);
                    }
                }
                if(bs.cnt==r)ans+=fpow(2,n-1-r);
            }
            ans%=mod;
            printf("%lld
    ",ans);
     
     
     
        }
        return 0;
    }
    
  • 相关阅读:
    正则函数及面向对象开发初识---day19
    正则计算器---day19
    正则表达式re模块---day18
    批量下载英雄联盟官网皮肤及打包
    zip压缩模块,tarfile压缩模块,包和模块,format格式化的复习--day17
    计算一个文件夹里面所有文件的大小---day17
    time模块,os操作系统及os模块和shutil模块用法---day16
    http请求方法
    cube.js
    http响应码
  • 原文地址:https://www.cnblogs.com/ttttttttrx/p/11432117.html
Copyright © 2011-2022 走看看