UOJ36【清华集训2014】玛里苟斯
给定序列 (a),每个元素有 (frac{1}{2}) 的概率被选择,设 (x) 表示被选择的元素的异或和,求 (x^k) 的期望。
(nle 10^5,kle 5,a_ige 0)
保证答案小于 (2^{63})
Solution
假设 (kge 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 ;
}