题意:给你n个数字,然后让你求所有满足异或和为0的子集的大小之和。
先对n个数求线性基,设线性基大小为r,可以分别计算线性基内数的贡献和线性基外数的贡献
1.线性基外:共n-r个数,枚举每个数x,将线性基外剩余的n-r-1个数任意排列,显然共有 2^(n−r−1)个集合,这些集合再异或x的结果还是能被线性基异或出,所以x的贡献为 2^(n−r−1)。
2.线性基内:枚举每个数x,将所有剩余的n-1个数再求一次线性基,设为B,分两种情况:
(1) x能被插入线性基。那么显然x不能在任意一个集合中出现,x的贡献为0。
(2) x不能被插入线性基。此时B的大小必定也为r,因为B已经能表示所有n个数了。那么在除去x和B的情况下,剩余n-r-1个数显然也是任意排列,x贡献为 2^(n−r−1)。
#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; }