链接:https://ac.nowcoder.com/acm/contest/881/H
来源:牛客网
题目描述
Bobo has a set A of n integers a1,a2,…,ana_1, a_2, \dots, a_na1,a2,…,an.
He wants to know the sum of sizes for all subsets of A whose xor sum is zero modulo (109+7)(10^9+7)(109+7).
Formally, find (∑S⊆A,⊕x∈Sx=0∣S∣) mod (109+7)\left(\sum_{S \subseteq A, \oplus_{x \in S} x = 0} |S|\right) \bmod (10^9+7)(∑S⊆A,⊕x∈Sx=0∣S∣)mod(109+7). Note that ⊕\oplus⊕ 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,…,ana_1, a_2, \dots, a_na1,a2,…,an.
* 1≤n≤1051 \leq n \leq 10^51≤n≤105
* 0≤ai≤10180 \leq a_i \leq 10^{18}0≤ai≤1018
* The number of test cases does not exceed 100.
* The sum of n does not exceed 2×1062 \times 10^62×106.
输出描述:
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个数构成的集合,求 满足集合内元素 异或为0 的所有子集的大小.
题目思路:我们可以根据集合之间有互异性,只要一个元素在这个集合中 ,他就会出现 一次,就有一次的贡献,所以我们可以算每个数对于答案的贡献 ,首先我们求出 n个数的线性基,假设其大小为r,因为这n个元素的线性基,线性基有性质:基内的的数可以表示整个集合S中的任意数,所以有a^b=c 所以 a^b^c=0,也就是说对于 基外任何一个数,基内都会有种选择使得 a^b^c=0,所以基外任何一个数都可以与其余的 n-r-1个数产生集合合并,而且这个集合中的毎一个数都可以找到 类似于a^b,所以每一个元素的贡献就是 2^(n-r-1),n-r个元素所以有 ans+=(n-r)*(2^(n-r-1)).
考虑基内的数,如果基内的数可以由其余的n-1个数表示出来,说明还存在一个线性基,我们知道 n个元素线性基大小是一定的,所以我们只需要判断这个数会不会对答案产生贡献,如果 这个数可以放到n-1的线性基中,说明不可以,如果不可以放到 就说明存在一种组合使得 a^b^c=0,所以我们只需要求出 其余n-1个数的线性基然后判断能否放进去即可,如果能放进去说明有贡献,否则就不能.
在判断基内的数的时候,可以先把r个放进去然后,copy一个数组复制第二个线性基,然后开始n^2遍历
最后得出AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const ll INF=1e9+5;
const int maxn=1e5+8;
const double PI=acos(-1);
const ll mod=1e9+7;
ll n,m;
ll x[101];
ll x1[101];
ll x2[101];
ll num[maxn];
ll num1[maxn];
ll num2[maxn];
ll sum[maxn];
bool build_judge(ll a,ll s[])//判断X线性基
{
for(int i=62;i>=0;i--)
{
if((1LL<<i)&a)
{
if(s[i+1])
a^=s[i+1];
else
{
s[i+1]=a;
break;
}
}
}
return a>0;
}
int main()
{
sum[0]=1;
for(int i=1;i<maxn;i++) sum[i]=(sum[i-1]*2)%mod;
while(~scanf("%llu",&n))
{
for(int i=0;i<=60;i++) x[i]=x1[i]=0;
ll ans=0,cot1=0,cot2=0;
for(int i=1;i<=n;i++)
scanf("%llu",&num[i]);
for(int i=1;i<=n;i++)
{
if(build_judge(num[i],x))num1[++cot1]=num[i];
else num2[++cot2]=num[i];
}
if(cot1==n) {printf("0\n");continue;}
ans=(ans+(n-cot1)*sum[n-cot1-1])%mod;
for(int i=1;i<=cot2;i++) build_judge(num2[i],x1);
for(int i=1;i<=cot1;i++)
{
for(int k=0;k<=62;k++) x2[k]=x1[k];
for(int k=1;k<=cot1;k++)
{
if(i==k) continue;
build_judge(num1[k],x2);
}
if(!build_judge(num1[i],x2))
ans=(ans+sum[n-cot1-1])%mod;
}
printf("%llu\n",ans);
}
return 0;
}
继续加油!!!