bzoj3811 玛里苟斯
Description
魔法之龙玛里苟斯最近在为加基森拍卖师的削弱而感到伤心,于是他想了一道数学题。
S 是一个可重集合,S={a1,a2,…,an}。
等概率随机取 S 的一个子集 A={ai1,…,aim}。
计算出 A 中所有元素异或 x, 求 xk 的期望。
Input
第一行两个正整数 n, k。
以下 n 行每行一个整数,表示 ai。
Output
如果结果是整数,直接输出。如果结果是小数(显然这个小数是有限的),输出精确值(末尾不加多余的 0)。
Sample Input
4 2
0
1
2
3
0
1
2
3
Sample Output
3.5
HINT
限制与约定
1≤n≤100000,1≤k≤5,ai≥0。最终答案小于 2^63 。k=1,2,3,4,5 各自占用 20% 的数据
正解:$dp$+线性基。
$k=1$比较简单,考虑把单独计算每一位。
如果有至少一个数这一位是$1$,那么很显然,这一位为$0$和为$1$的概率相等,都是$0.5$;否则这一位只可能是$0$。
$k=2$其实差不多,但是我还是没想到。。
考虑枚举异或以后的数的二进制任意两位的平方,当这两位的平方有贡献当且仅当这两位都是$1$。
然后计算一下这两位都是$1$的概率,假设两位分别为$i,j$,那么这两位组合的期望就是$2^{i+j}*p$。
$p$也比较好算,如果所有数在$i$和$j$两位都相等的话那么概率就是$0.5$,否则概率就是$0.25$。
$k>=3$时,因为题目说答案小于$2^{63}$,那么每个数肯定最多只有$22$位。
根据线性基的性质,$n$个数异或以后的数出现概率与线性基中这个数出现概率相同。
假设线性基元素有$k$个,那么$n$个数异或以后每个数出现概率就是$\frac{1}{2^{k}}$,于是我们直接写一个爆搜,搜出线性基的所有异或情况就行了。
1 #include <bits/stdc++.h> 2 #define il inline 3 #define RG register 4 #define ull unsigned long long 5 6 using namespace std; 7 8 ull a[100010]; 9 int n,k; 10 11 il ull gi(){ 12 RG ull x=0,q=1; RG char ch=getchar(); 13 while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); 14 if (ch=='-') q=-1,ch=getchar(); 15 while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); 16 return q*x; 17 } 18 19 namespace solve1{ 20 21 ull ans; 22 23 int main(){ 24 for (RG int i=1;i<=n;++i) ans|=a[i]; 25 printf("%llu",ans>>1); 26 puts((ans&1)?".5":""); 27 return 0; 28 } 29 30 } 31 32 namespace solve2{ 33 34 ull ret,res,ans; 35 36 int main(){ 37 for (RG int i=1;i<=n;++i) ret|=a[i]; 38 for (RG int i=0;i<32;++i) 39 for (RG int j=0,fg=0;j<32;++j,fg=0) 40 if ((ret>>i&1) && (ret>>j&1)){ 41 for (RG int p=1;p<=n;++p) 42 if ((a[p]>>i&1)^(a[p]>>j&1)){ fg=1; break; } 43 if (i+j-1-fg<0) ++res; else ans+=1llu<<(i+j-1-fg); 44 } 45 ans+=res>>1,printf("%llu",ans); 46 puts((res&1)?".5":""); return 0; 47 } 48 49 } 50 51 namespace solve3{ 52 53 ull p[30],tot,ans,rhl; 54 int Sz; 55 56 il ull qpow(RG ull a,RG int b){ 57 RG ull ans=1; 58 while (b){ 59 if (b&1) ans*=a; a*=a,b>>=1; 60 } 61 return ans; 62 } 63 64 il void insert(RG ull x){ 65 for (RG int i=Sz;i>=0;--i){ 66 if (!(x>>i&1)) continue; 67 if (!p[i]){ p[i]=x; break; } 68 x^=p[i]; 69 } 70 return; 71 } 72 73 il void dfs(RG int x,RG ull S){ 74 if (x>Sz){ 75 RG ull res=1; 76 for (RG int i=1;i<k;++i) res*=S; 77 if (res<rhl){ 78 res*=S,tot+=res; 79 if (tot>=rhl) ans+=tot/rhl,tot%=rhl; 80 } else{ 81 ans+=res/rhl*S,res%=rhl,res*=S,tot+=res; 82 if (tot>=rhl) ans+=tot/rhl,tot%=rhl; 83 } 84 return; 85 } 86 dfs(x+1,S),dfs(x+1,S^p[x]); return; 87 } 88 89 int main(){ 90 if (k==3) Sz=21; if (k==4) Sz=15; if (k==5) Sz=12; 91 for (RG int i=1;i<=n;++i) insert(a[i]); 92 rhl=1<<(Sz+1),dfs(0,0),printf("%llu",ans); 93 puts(tot?".5":""); return 0; 94 } 95 96 } 97 98 int main(){ 99 #ifndef ONLINE_JUDGE 100 freopen("maligous.in","r",stdin); 101 freopen("maligous.out","w",stdout); 102 #endif 103 n=gi(),k=gi(); 104 for (RG int i=1;i<=n;++i) a[i]=gi(); 105 if (k==1) solve1::main(); 106 if (k==2) solve2::main(); 107 if (k>=3) solve3::main(); 108 return 0; 109 }