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

Description
已知一个长度为n的正整数序列A(下标从1开始), 令 S = { x | 1 <= x <= n }, S 的幂集2^S定义为S 所有子
集构成的集合。定义映射 f : 2^S -> Zf(空集) = 0f(T) = XOR A[t] , 对于一切t属于T现在albus把2^S中每个集
合的f值计算出来, 从小到大排成一行, 记为序列B(下标从1开始)。 给定一个数, 那么这个数在序列B中第1
次出现时的下标是多少呢?
Input
第一行一个数n, 为序列A的长度。接下来一行n个数, 为序列A, 用空格隔开。最后一个数Q, 为给定的数.
Output
共一行, 一个整数, 为Q在序列B中第一次出现时的下标模10086的值.
Sample Input
3
1 2 3
1
Sample Output
3
样例解释:
N = 3, A = [1 2 3]
S = {1, 2, 3}
2^S = {空, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}}
f(空) = 0
f({1}) = 1
f({2}) = 2
f({3}) = 3
f({1, 2}) = 1 xor 2 = 3
f({1, 3}) = 1 xor 3 = 2
f({2, 3}) = 2 xor 3 = 1
f({1, 2, 3}) = 0
所以
B = [0, 0, 1, 1, 2, 2, 3, 3]
HINT
数据范围:
1 <= N <= 10,0000
其他所有输入均不超过10^9
Source
湖北省队互测


s o l u t i o n solution
线性基模板题
先把线性基构出来,那么小于 k k 的每个能由线性基构出来的数都有 2 n r 2^{n-r} 种方案,其中 n n 为数的总个数, r r 为线性基里面的元素个数。原因比较显然。

然后只要从大到小扫一遍线性基就做完了

#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x],y = e[i].y;i;i = e[i].n,y = e[i].y)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back 
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define ll long long
int rd()
{
	int num = 0;char c = getchar();bool flag = true;
	while(c < '0'||c > '9') {if(c == '-') flag = false;c = getchar();}
	while(c >= '0' && c <= '9') num = num*10+c-48,c = getchar();
	if(flag) return num;else return -num;
}
const int p = 10086;
int n,cnt;
int v[101000];
int a[60],bin[60];
int main()
{
	n = rd();
	bin[0] = 1;rep(i,1,31) bin[i] = (bin[i-1]<<1)%p;
	rep(i,1,n) v[i] = rd();
	rep(i,1,n)
	{
		repp(j,31,0)
		    if(v[i]>>j&1)
		    {
		    	if(!a[j]) {a[j] = i;break;}
		    	else v[i] ^= v[a[j]];
		    }
		if(v[i] == 0) cnt++;
	}
	int tmp = 1;
	rep(i,1,cnt) tmp = (tmp<<1)%p;
	repp(j,31,0)
	    rep(i,1,n)
	        if(a[j] != i && (v[i]>>j&1))
	            v[i] ^= v[a[j]];
	int k = rd(),now = 0,tot = n,ans = k!=0;
	sort(v+1,v+n+1);reverse(v+1,v+n+1);
	while(!v[tot]) tot--;
	rep(i,1,tot)
	    if((now^v[i]) < k)
	    {
	    	now ^= v[i];
	    	ans = (ans + bin[tot-i])%p;
	    }
	ans = 1ll*ans*tmp%p;
	ans = (ans+1)%p;
	printf("%d\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/a1035719430/article/details/85194036