albus就是要第一个出场:线性基

已知一个长度为n的正整数序列A(下标从1开始), 令 S = { x | 1 <= x <= n },

S 的幂集2^S定义为S 所有子集构成的集合。

定义映射 f : 2^S -> Z

f(空集) = 0

f(T) = XOR A[t](异或和)

 对于一切t属于T现在albus把2^S中每个集合的f值计算出来, 从小到大排成一行, 记为序列B(下标从1开始)。

给定一个数, 那么这个数在序列B中第1次出现时的下标是多少呢?

呃啊啊还我们一个可视的题面。

这是个结论题。。。

结论:

n个数构成的线性基有k个时,那么这n个数的全部子集的异或和刚好就是线性基k个数能拼成的2k个数,每个数有2n-k个。

证明也许比较显然?

然后这题就可做了。

好无聊。。。结论题什么的。。。

但是有什么办法呢?只能记住吧。

写这篇博客的目的就是为了存一下结论。

以及推荐blog:rvalue

里面有结论的感性证明。

有了结论,代码倒挺好写的。

 1 #include<cstdio>
 2 #define mod 10086
 3 int pw(int b,int t,int a=1){for(;t;t>>=1,b=b*b%mod)if(t&1)a=a*b%mod;return a;}
 4 int base[33];
 5 int main(){
 6     int n,N,x,cnt=0,ans=0;scanf("%d",&n);N=n;
 7     while(n--){
 8         scanf("%d",&x);
 9         for(int i=30;~i;--i)if(!base[i]&&x&1<<i){base[i]=x;break;}
10             else if(x&1<<i)x^=base[i];
11     }
12     scanf("%d",&x);
13     for(int i=30;~i;--i)if(base[i]&&x&1<<i)cnt++,ans=(ans+pw(2,N-cnt))%mod;
14         else if(base[i])cnt++;
15     printf("%d\n",ans+1);
16     
17 }
View Code

猜你喜欢

转载自www.cnblogs.com/hzoi-DeepinC/p/11624654.html