题目大意:给定一个n个数的集合S和一个数x,求x在S的2^n个子集从大到小的异或和序列中最早出现的位置
有学长真好不用自己打题目大意了233
首先我们求出线性基 我们会得到一些从大到小排列的数和一堆0 记录0的个数
不考虑0,看前面的数,由于线性基的性质,我们直接贪心从大到小枚举 若当前异或和异或这个值小于Q则取这个数 (注意^不要写成+或者| 本蒟蒻已经因为这个WA了两道题了
然后我们通过每个数取不取可以得到一个01序列 这个序列就是通过异或可以得到的小于Q的数的数量的二进制
比如线性基是8 4 2 Q=13 取完8和4之后无法法取2 那么得到的01序列就是110 即6
然后我们再加上空集的0
然后考虑后面的0 设有m个0 那么每个数出现的次数为2^m 乘起来后+1就是答案
一个细节就是当Q=0的时候计算小于Q的数的数量时不要算上0 不懂的可以自己测测0
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 100100
#define Mo 10086
using namespace std;
int n,m,q,ans,a[M];
void Gaussian_Elimination()
{
int i,j,k=0;
for(j=1<<30;j;j>>=1)
{
for(i=k+1;i<=n;i++)
if(a[i]&j)
break;
if(i==n+1)
continue;
swap(a[i],a[++k]);
for(i=1;i<=n;i++)
if(i!=k)
if(a[i]&j)
a[i]^=a[k];
}
m=n-k;
n=k;
}
int ksm(int x,int y)
{
int re=1;
while(y)
{
if(y&1)re*=x,re%=Mo;
x*=x,x%=Mo;
y>>=1;
}
return re;
}
int main()
{
int i,num,now=0;
cin>>n;
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
Gaussian_Elimination();
cin>>q;
for(i=1;i<=n;i++)
if( (now^a[i])<q )
ans+=ksm(2,n-i),ans%=Mo,now^=a[i];
if(q)
++ans,ans%=Mo;
ans*=ksm(2,m),ans%=Mo;
++ans,ans%=Mo;
cout<<ans<<endl;
}