玛里苟斯[清华集训2014 Day1]
魔法之龙玛里苟斯最近在为加基森拍卖师的削弱而感到伤心,于是他想了一道数学题。
S 是一个可重集合,S={a1,a2,…,an}。
等概率随机取 S 的一个子集 A={ai1,…,aim}。
计算出 A 中所有元素异或 x, 求 xk 的期望。
SOL :
这题目太色情了。没打高精度炸的不要不要的。
我们观察一波局势,发现当K=1时我们可以按位异或,我们可以证明,若 S集合中存在X 在 i位是1,那么这一位上出现1的期望就是0.5.
证明如下,我们把每一位上的ai的值取出来,那么我们发现0对答案没有贡献。设我们有X个1,而我们取偶数个1的期望为 signma C(2i+1,x)=((1+1)^n+(1-1) ^ n)/2;
而总数为2^n,那么我们的期望就是0.5.
所以我们统计每一位上是否有1,最后累加除2.
K=2:我们依旧统计每一位上是否有1.
我们发现我们得到每一位上有1的位对答案
∑j=0m∑p=0m(∑2ni=1bi,j⋅bi,p2n⋅2j+p)
我们就可以将其答案统计出来。
K>2 我们惊奇的发现,对S其进行求线性基其答案不变。我们发现K>2时由于答案在LongLong范围内,我们可以保证求出得基最多22个,
暴力统计答案即可。
#pragma optimize("-O2") #include<bits/stdc++.h> #define sight(c) ('0'<=c&&c<='9') #define LL unsigned long long #define N 100009 #define db long double const LL mo=(1<<25)-1; using namespace std; struct NL{ LL a,b; NL() {a=b=0;} NL(LL x,LL y):a(x),b(y){} inline NL operator ^(const NL &A)const &{ return NL(A.a^a,A.b^b); } inline NL operator ^(const LL &A)const &{ return NL(a,A^b); } inline NL operator +(const NL &A)const &{ NL T; T.a=A.a+a; T.b=A.b+b; if (T.b>mo) T.a+=T.b>>25,T.b&=mo; return T; } inline NL operator +(const LL &A)const &{ NL T; T.a=a; T.b=A+b; if (T.b>mo) T.a+=T.b>>25,T.b&=mo; return T; } inline NL operator *(const NL &A)const &{ NL T; T.a=(A.a*a<<25)+A.a*b+A.b*a; T.b=A.b*b; if (T.b>mo) T.a+=T.b>>25,T.b&=mo; return T; } inline NL operator *(const LL &A)const &{ NL T; T.a=a*A; T.b=A*b; if (T.b>mo) T.a+=T.b>>25,T.b&=mo; return T; } inline LL ok(int x){ LL T=b&(1ll<<x)-1; b>>=x; b|=(a&(1ll<<x)-1)<<(25-x);a>>=x; return T; } }; inline void read(LL &x){ static char c; for (c=getchar();!sight(c);c=getchar()); for (x=0;sight(c);c=getchar()) x=x*10+c-48; } void write(LL x) { if (x<10) { putchar('0'+x); return;} write(x/10); putchar('0'+x%10); } inline void writeln(LL x) { if (x<0) putchar('-'),x*=-1; write(x); putchar(' '); } LL n,k,ans,X,A[N],P[65],r,OT[65],O; NL Ans; void Guass() { for (int i=1;i<=n;i++) for (int j=62;~j;j--) if ((A[i]>>j)&1) if (!P[j]) {P[j]=A[i]; break;} else A[i]^=P[j]; for (int j=0;j<=62;j++) if (P[j]) OT[r++]=P[j]; } int b[79]; inline NL pow(NL x,int k){ NL anw=NL(0,1); for (;k;k>>=1,x=x*x)if (k&1) anw=anw*x; return anw; } void dfs(NL x,int t){ if (!(t^r)) { Ans=Ans+pow(x,k); return;} dfs(x^OT[t],t+1); dfs(x,t+1); } int main () { freopen("malygos.in","r",stdin); freopen("malygos.out","w",stdout); read(n); read(k); for (int i=1;i<=n;i++) { read(A[i]); for (int j=0;j<=63;j++) b[j]|=(A[i]>>j)&1; } if (k==1) { for (int j=63;~j;j--) if (b[j]) ans+=1ll<<j; write(ans>>1); if (ans&1) puts(".5 "); return 0; } if (k==2) { for (int j=31;~j;j--) if (b[j]) Ans=Ans+(1ull<<2*j+1); for (int i=31;~i;i--) { for (int j=0;j<i;j++) { int c[4]={}; for (int k=1;k<=n;k++) c[(A[k]>>i&1)<<1|(A[k]>>j&1)]=1; for (int k=0;k<4;k++) for (int ii=0;ii<4;ii++) for (int jj=0;jj<4;jj++) if (c[ii]&&c[jj]) c[ii^jj] = 1; int s=0; for (int k=0;k<4;k++) s+=c[k]; if (c[3]) Ans=Ans+((LL)(8/s)*(1ULL<<i+j)); }} LL g=Ans.ok(2); LL T=(Ans.a<<25)+Ans.b; write(T); LL MM=1<<2; if (g) { putchar('.'); while (g) {g*=10; putchar('0'+g/MM); g%=MM;} } return 0; } Guass(); dfs(NL(0,0),0); LL g=Ans.ok(r); LL T=(Ans.a<<25)+Ans.b; write(T); LL MM=1<<r; if (g) { putchar('.'); while (g) { g*=10; putchar('0'+g/MM); g%=MM;} } return 0; }