2019牛客暑期多校訓練營(第一場):XOR(線性基)

題意:給定數組,求全部異或起來爲0的集和的大小之和。c++

思路:因爲是集合大小,咱們換成考慮每一個元素在多少個集合裏有貢獻。 先生成線性基。數組

對於沒有插入線性基的元素x,貢獻是2^(N-base-1),由於x選擇以後,其餘非基元素不管選仍是不選,均可以調整基來使得異或和爲0。ide

對於插入線性基的元素x,咱們也一樣這樣考慮,把除了它的N-1個數生成線性基。 就能夠一樣算貢獻了。 這裏如今能夠稍加優化,把最開始的非基元素預處理成一個線性基,這樣生成新的線性基就快起來了。優化

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define rep2(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int maxn=2000010;
const int Mod=1e9+7;
ll a[maxn],b[maxn],c[maxn],used[maxn]; int tot;
int qpow(int a,int x){
    int res=1; while(x){
        if(x&1) res=1LL*res*a%Mod;
        x>>=1; a=1LL*a*a%Mod;
    } return res;
}
bool add(ll x,ll base[])
{
    rep2(i,63,0) {
        if(x&(1LL<<i)){
            if(!base[i]){ base[i]=x; return true;}
            x^=base[i];
        }
    }
    return false;
}
int main()
{
    int N,ans=0;  ll x;
    while(~scanf("%d",&N)){
       rep(i,0,63) a[i]=b[i]=c[i]=0; tot=0;
       rep(i,1,N) {
          scanf("%lld",&x);
          if(add(x,a)) used[++tot]=x;
          else add(x,b);
       }
       if(tot<N) ans=1LL*qpow(2,N-tot-1)*(N-tot)%Mod;
       rep(i,1,tot){
           rep(j,0,63) c[j]=b[j];
           rep(j,1,tot) if(i!=j) add(used[j],c);
           if(!add(used[i],c)) (ans+=qpow(2,N-tot-1))%=Mod;
       }
       printf("%d\n",ans);
    }
    return 0;
}

 

It is your time to fight!
相關文章
相關標籤/搜索