【bzoj2844】 albus就是要第一個出場

http://www.lydsy.com/JudgeOnline/problem.php?id=2844 (題目連接)php

題意

  給出${n}$個數,它們能夠異或出${n^2}$個數,將這些數從小到大排列起來,問${Q}$最先出現的位置。ios

Solution

  原來線性基還有這種性質,我怎麼不知道→_→spa

  假設${n}$個數能夠消出${k}$個線性基,那麼顯然會有${2^k}$個不一樣的亦或和,${n}$個數相互排列顯然會有${2^n}$個。神奇的事情就在於每種亦或和竟然是同樣多的,也就是都是${2^{n - k}}$個。blog

  因此這道題就這樣作了,高斯消元消成對角矩陣,從高位往低位若是異或上這個數以後小於${Q}$,那就異或上它。因而咱們能夠獲得一個二進制數,這個二進制數就是排在它前面的能夠被異或出來的數的個數(注意這裏並無計算重複的),又由於每一個異或和都出現了${2^{n-k}}$次,因此最後答案就是排在它前面的數的個數乘上${2^{n-k}}$再加上${1}$就是${Q}$最先出現的位置。get

細節

  注意${0}$是一種不一樣的異或和,也就是說${0}$這個異或和也出現了${2^{n-k}}$次。string

代碼

// bzoj2844
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<complex>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define MOD 10086
#define inf 1ll<<60
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;

const int maxn=100010;
int a[maxn],bin[32],n,m,Q;

void Gauss() {
	m=0;
	for (int i=bin[30];i;i>>=1) {
		int j=m+1;
		while (j<=n && !(a[j]&i)) j++;
		if (j==n+1) continue;
		swap(a[++m],a[j]);
		for (j=1;j<=n;j++) if (j!=m && a[j]&i) a[j]^=a[m];
	}
}
int power(int a,int b) {
	int res=1;
	while (b) {
		if (b&1) res=res*a%MOD;
		b>>=1;a=a*a%MOD;
	}
	return res;
}
int main() {
	bin[0]=1;for (int i=1;i<=30;i++) bin[i]=bin[i-1]<<1;
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
	Gauss();
	scanf("%d",&Q);
	int now=0,ans=0;
	for (int i=1;i<=m;i++) if ((now^a[i])<Q) ans=(ans+power(2,m-i))%MOD,now^=a[i];
	if (Q!=0) ans=(ans+1)%MOD;
	ans=(ans*power(2,n-m))%MOD;
	printf("%d",(ans+1)%MOD);
	return 0;
}
相關文章
相關標籤/搜索