【清華集訓2014】瑪裡苟斯
阿新 • • 發佈:2020-10-09
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 ; }