线性基bzoj2844: albus就是要第一个出场
Posted AntiQuality
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线性基bzoj2844: albus就是要第一个出场相关的知识,希望对你有一定的参考价值。
线性基求可重rank
题目描述
给定 n 个数 $\{ a_i \}$ ,以及数 $x$。
将 $\{ a_i \}$? 的所有子集(包括空集)的异或值从小到大排序,得到 $\{ b_i \} $。
求 $x$ 在 $\{ b_i \}$ 中第一次出现的下标。保证 $x$ 在 $\{ b_i \}$ 中出现。
HINT
数据范围:
1 <= N <= 10,0000
其他所有输入均不超过10^9
题目分析
考虑线性基求rank的过程,是一个求第k大的逆过程。也就是首先对线性基消元,再把线性基的元素给排出来,继而考虑每一位被线性基内第几个元素控制。
而现在是一个可重集,于是{1,1}和{1,1,1,1,1}就成了截然不同的两种情况。记线性基内有$legal$个元素,那么剩下就是$n-legal$个可被线性基表示的数字(下面简称无关数字)。沿用线性基题的一类思维方式,考虑这类无关数字对于线性基的影响。我们会发现,不论选出哪一部分无关数字(共$2^{n-legal}$种情况),都有且仅有一种“在线性基内选数”的方式使得选出的无关数字被重新异或为0.也就是说,记原rank为$preRank$,可重集rank就是$preRank*2^{n-legal}+1$。
对了,求原rank时候记得要和第k大操作一样把线性基元素重新拎出来。
1 #include<bits/stdc++.h> 2 const int maxn = 100035; 3 const int MO = 10086; 4 5 int n,p[103],ans,legal; 6 7 int read() 8 { 9 char ch = getchar(); 10 int num = 0, fl = 1; 11 for (; !isdigit(ch); ch = getchar()) 12 if (ch==‘-‘) fl = -1; 13 for (; isdigit(ch); ch = getchar()) 14 num = (num<<1)+(num<<3)+ch-48; 15 return num*fl; 16 } 17 void insert(int x) 18 { 19 for (int i=30, chk=0; i>=0&&!chk; i--) 20 if (x>>i){ 21 if (p[i]) x ^= p[i]; 22 else{ 23 p[i] = x, chk = 1, ++legal; 24 for (int j=30; j>i; j--) 25 if (p[j]>>i) p[j] ^= p[i]; 26 } 27 } 28 } 29 void query(int x) 30 { 31 int i,j; 32 for (i=0, j=0; i<=30; i++) 33 if (p[i]) p[j] = i, ++j; 34 for (i=j-1; i>=0; i--) 35 if ((1<<p[i])&x) ans += (1<<i); 36 } 37 int qmi(int a, int b) 38 { 39 int ret = 1; 40 for (a%=MO; b; b>>=1, a=a*a%MO) 41 if (b&1) ret = ret*a%MO; 42 return ret; 43 } 44 int main() 45 { 46 n = read(); 47 for (int i=1; i<=n; i++) insert(read()); 48 query(read()); 49 ans = (1ll*ans*qmi(2, n-legal)%MO+1)%MO; 50 printf("%d\n",ans); 51 return 0; 52 }
END
以上是关于线性基bzoj2844: albus就是要第一个出场的主要内容,如果未能解决你的问题,请参考以下文章