1. 程式人生 > >【BZOJ2844】albus就是要第一個出場 高斯消元求線性基

【BZOJ2844】albus就是要第一個出場 高斯消元求線性基

子集 高斯 efi continue clas sum ext ++ pre

【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

題解:一開始想的是二分,結果發現這並不是某HDU原題。。。

查了題解才不得不再次承認一個顯而易見但是不會證的結論:每個數在序列中出現的次數是相同的,次數都是n-線性基大小+1(好吧我說的不規範) 現在問題可以轉化成所有用線性基可以組合出來的數中,有多少個比Q小的,依舊是按位貪心,如果當前位比Q小,那麽下面能組合出的所有數都比Q小,直接計算答案
#include <cstdio>
#include <cstring>
#include <iostream>
#define mod 10086
using namespace std;
const int maxn=100010;
int n,m,tot,ans,sum;
int v[maxn];
int main()
{
	scanf("%d",&n);
	int i,j;
	for(i=1;i<=n;i++)	scanf("%d",&v[i]);
	scanf("%d",&m);
	if(m==0)
	{
		printf("1");
		return 0;
	}
	for(i=1<<30;i;i>>=1)
	{
		for(j=++tot;j<=n;j++)	if(v[j]&i)
		{
			swap(v[tot],v[j]);
			break;
		}
		if(!(v[tot]&i))
		{
			tot--;
			continue;
		}
		for(j=1;j<=n;j++)	if((v[j]&i)&&j!=tot)	v[j]^=v[tot];
	}
	for(i=1;i<=tot;i++)	if((sum^v[i])<m)	sum^=v[i],ans|=(1<<tot-i);
	ans=(ans+1)%mod;
	for(i=1;i<=n-tot;i++)	ans<<=1,ans%=mod;
	printf("%d",(ans+1)%mod);
	return 0;
}

【BZOJ2844】albus就是要第一個出場 高斯消元求線性基