链接:https://ac.nowcoder.com/acm/contest/881/H
来源:牛客网
题目描述
Bobo has a set A of n integers a1,a2,…,an.
He wants to know the sum of sizes for all subsets of A whose xor sum is zero modulo.
Formally, find mod
. Note that ⊕ denotes the exclusive-or (XOR).
输入描述:
The input consists of several test cases and is terminated by end-of-file.
The first line of each test case contains an integer n.
The second line contains n integers a1,a2,…,an.
*
*
* The number of test cases does not exceed 100.
* The sum of n does not exceed .
输出描述:
For each test case, print an integer which denotes the result.
示例1
输入
1
0
3
1 2 3
2
1000000000000000000 1000000000000000000
输出
1
3
2
题目分析:
题意要求计算n个数a[1...n]中,选出若干元素构成集合S,满足异或和为0的集合S的大小之和。
可以将所求转换成计算每个元素出现在异或和为0的集合中多少次,将每个元素的次数累加起来就是答案。
做法:
个元素构造出一组线性基
,构成线性基的
个数暂存起来,
剩下的个数字,总共构成了
个集合,
每个集合都能被线性基唯一表示出来(添加若干个基后集合异或和变为0),
这个元素中,每个元素出现在异或和为0的集合中的次数为
(自己在集合中,其他元素任意)
先用其他个元素构造一组线性基
.
对于构成线性基的数字的计数:
复制线性基到线性基
,将线性基
中除了
之外其他
个元素加入
中,
检验能否被
所表示,若可以,答案贡献为
(
表示线性基
中元素个数),
若不可以,说明与其他n-1个数字均线性无关,
答案贡献为0
代码:
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const ll mod = 1e9+7;
ll poww(ll a, ll b){
ll res = 1;
while(b){
if(b&1) res = res * a %mod;
a = a*a % mod;
b >>= 1;
} return res;
}
int n;
ll a[100005];
ll r[64], b[64], p[64];
bool add(ll a[], ll x){
for(int i = 63; i >= 0; i --)
if(x & (1ll<<i)){
if(a[i])
x ^= a[i];
else{
a[i] = x;
return true;
}
}
return false;
}
int main(){
while(~scanf("%d", &n)){
vector<ll> R;
for(int i = 0; i < 64; i ++) r[i] = b[i] = 0;
int bcnt = 0;
for(int i = 1; i <= n; i++){
scanf("%lld", &a[i]);
if(add(r, a[i]))
R.push_back(a[i]);
else
bcnt += add(b, a[i]);
}
ll ans = poww(2,n-R.size()-1)*(n-R.size())%mod;
for(int i = 0; i < R.size(); i++){
memcpy(p, b, sizeof b);
int pcnt = bcnt;
for(int j = 0; j < R.size(); j++)
if(j != i) pcnt += add(p, R[j]);
if(!add(p, R[i]))
ans += poww(2,n-pcnt-1);
}
ans %= mod;
printf("%lld\n", ans);
}
return 0;
}