就是要第一个出场的albus 【BZOJ】 线性基

 

就是我代码里读入之后的那一部分。

1.(一下a[]为原数组 a'[]为线性基)

线性基 中的a'[i]其实 是 原来的a[]中的某个子集(2^n个子集中的某个) 异或出来的  可能会有其他的子集与它异或和相同,a'[i]代表了 这个集合。

线性基的大小是log的,因为  a[]中异或和等于a'[i]的集合可能有好多   而线性基则 通过异或消掉了这些 重复的。

2.

假设a[]大小为n  线性基大小为k,则a[]和a'[] 都有且仅有2^k种 异或和不同 的子集【清楚线性基定义的话 这是显然的】

然而由于本题 要保留重复的, 那么另一个性质就是 a'[]可异或出的2^k种异或和  在a[]可异或出的2^n个有重复的值中 每个不同的值都有2^(n-k)个。

所以最后ans要*2^(n-k) 

 1 #include <bits/stdc++.h>
 2 #define mo 10086
 3 using namespace std;
 4 int b[50],a[100005],n,m,k,t,x,y,z,p,q,ans;
 5 int main(){
 6     scanf("%d",&n);
 7     for (int i=1;i<=n;++i) scanf("%d",&a[i]);
 8     scanf("%d",&m); k=0;
 9     for (int i=1<<29;i;i>>=1){
10         for (int j=k+1;j<=n;++j)
11         if (a[j]&i){
12             swap(a[j],a[++k]); b[k]=i;
13             for (int o=1;o<=n;++o)
14             if (o!=k&&a[o]&i) a[o]^=a[k];
15             break;
16         }
17     }
18     for (int i=1;i<=k;++i)
19     if ((x^a[i])<=m){
20         x^=a[i];
21         (ans+=(1<<k-i)%mo)%=mo;
22     }
23     for (int i=k+1;i<=n;++i) (ans<<=1)%=mo;
24     ++ans%=mo; printf("%d",ans);
25     return 0;
26 }
Archer

 

posted @ 2017-03-07 19:46  cyz666  阅读(114)  评论(0编辑  收藏  举报