【清华集训2014】玛里苟斯

UOJ36【清华集训2014】玛里苟斯

给定序列 \(a\),每个元素有 \(\frac{1}{2}\) 的概率被选择,设 \(x\) 表示被选择的元素的异或和,求 \(x^k\) 的期望。

\(n\le 10^5,k\le 5,a_i\ge 0\)

保证答案小于 \(2^{63}\)

Solution

假设 \(k\ge 3\),那么可以注意到值域会大概是 \(\sqrt{2^{63}}\) 这个级别。

所以线性基很小,由于每种值的出现次数都相同(线性基的推论)所以每种值对答案的贡献都是 \(\frac{x^k}{2^{cnt}}\)

否则如果 \(k=1\),那么只需要考虑每一位的贡献。

\(k=2\) 就考虑一下每两位的贡献即可。

当然,仍然只需要保留线性基的元素,这样的话就不会除非常大的数。

然后这个题有结论,答案最多只能是 \(x.5\),所以特判一下即可

\(Code:\)

#include<bits/stdc++.h>
using namespace std ;
#define Next( i, x ) for( register int i = head[x]; i; i = e[i].next )
#define rep( i, s, t ) for( register int i = (s); i <= (t); ++ i )
#define drep( i, s, t ) for( register int i = (t); i >= (s); -- i )
#define re register
#define int __int128
int gi() {
	char cc = getchar() ; int cn = 0, flus = 1 ;
	while( cc < '0' || cc > '9' ) {  if( cc == '-' ) flus = - flus ; cc = getchar() ; }
	while( cc >= '0' && cc <= '9' )  cn = cn * 10 + cc - '0', cc = getchar() ;
	return cn * flus ;
}
const int N = 1e5 + 5 ; 
const int M = 100 + 5 ; 
int n, K, cnt, tmp[M], s[M], C[M][M], fc[150] ;
int Ans ; 
void insert(int x) {
	drep( i, 0, 64 ) if((x >> i) & 1) {
		if( tmp[i] ) x ^= tmp[i] ;
		else tmp[i] = x, x = 0 ;
	}
}
int fpow(int x, int k) {
	int ans = 1, base = x ;
	while(k) {
		if(k & 1) ans = ans * base ;
		base = base * base, k >>= 1 ;
	} return ans ;
}
void Dfs(int x, int S) {
	if(x == cnt + 1) return Ans += fpow(S, K), void() ; 
	Dfs(x + 1, S), Dfs(x + 1, S ^ s[x]) ;
}
void write() {
	int iv = (1ll << cnt) ; 
	int d = Ans / iv ; 
	printf("%llu", (unsigned long long)(d) ) ;
	if( d * iv < Ans ) printf(".5") ; 
}
void Solve1() {
	Dfs(1, 0), write() ; 
}
void Solve2() {
	fc[0] = 1 ; rep( i, 1, 100 ) fc[i] = fc[i - 1] * 2 ; 
	rep( i, 0, 62 ) rep( j, 0, 62 ) {
		if( i + j > 100 ) continue ; 
		int a = 0, b = 0, c = 0, r = 0, d = fc[i + j] ;
		rep( k, 1, cnt ) if((s[k] >> i) & 1) ++ a ;
		rep( k, 1, cnt ) if((s[k] >> j) & 1) ++ b ;
		rep( k, 1, cnt ) if(((s[k] >> i) & 1) && ((s[k] >> j) & 1)) ++ c ; 
		a -= c, b -= c ; 
		if( (!a) && (!c) && (!b) ) continue ;  
		rep( k, 0, c ) {
			int f = 0, g = 0 ;
			if(k & 1) {
				rep(l, 0, a) if(!(l & 1)) f += C[a][l] ;
				rep(l, 0, b) if(!(l & 1)) g += C[b][l] ;
				r += C[c][k] * f * g ; 
			}
			else {
				rep(l, 0, a) if((l & 1)) f += C[a][l] ;
				rep(l, 0, b) if((l & 1)) g += C[b][l] ;
				r += C[c][k] * f * g ; 
			}
		} 
		Ans += d * r * (1ll << (cnt - a - b - c)) ; 
	} write() ; 
}
void Solve3() {
	rep( j, 1, cnt ) Ans |= s[j] ;
	cnt = 1 ; write() ; 
}
signed main()
{
	n = gi(), K = gi() ; int x ;
	rep( i, 1, n ) x = gi(), insert(x) ; 
	rep( i, 0, 64 ) if(tmp[i]) s[++ cnt] = tmp[i] ;
	C[0][0] = 1 ; 
	rep( i, 1, 64 ) rep( j, 0, 64 ) C[i][j] = (!j) ? 1 : (C[i - 1][j - 1] + C[i - 1][j]) ; 
	if( K >= 3 ) Solve1() ; 
	else if( K == 2 ) Solve2() ;
	else Solve3() ; 
	return 0 ;
}
posted @ 2020-10-09 10:21  Soulist  阅读(144)  评论(0编辑  收藏  举报