[清华集训2014]玛里苟斯
因为\(Ans<=2^{63}\)所以根据不同的\(k\)值,所有数的位数\(m\)是不一样的,\(k\)越大,\(m\)越小。
\(Ans=\sum_{i_1=1}^m\sum_{i_2=1}^m...\sum_{i_k=1}^m(2^{\sum_{j=1}^ki_j}E(\prod_{j=1}^kbit(xor(A\subset S))))\)
那么就很显然了,求出\(k\)位全都为1的概率,再乘上前面一坨鸟不拉屎的东西即可。
那么这个概率应该怎么算呢?
我们先用原来的\(n\)个数构造线性基,那么现在我们只需要用63个数就得到了原来的线性空间。
再从63个数中挑出这\(k\)位构造另一个线性基。
如果这一个新构造的线性基能表示出每一位都为1的数,那么它的概率就是\(\frac{2^{n-cnt}}{2^n}=\frac{1}{2^{cnt}}\)(其中\(cnt\)为线性基中有值的位的个数)
然后,就没有然后了。。。
注意:
- unsigned long long 坑的很
#include<bits/stdc++.h>
#define ull unsigned long long
using namespace std;
int n,k,cnt;
ull bit[70],need[70],c[7][7],x;
struct FT{
ull x;bool be;
FT operator +(FT b){
if (be&&b.be) return (FT){x+b.x+1,false};
return (FT){x+b.x,be|b.be};
}
} ans;
struct base{
int n;
ull b[70];
void init(int len){
n=len;
memset(b,0,sizeof(b));
}
void insert(ull x){
for (int i=n;i>=0&&x;i--)
if (x>>i&1)
if (b[i]) x^=b[i];
else {b[i]=x;break;}
}
bool check(ull x){
ull res=0;
for (int i=n;i>=0;i--){
if (!b[i]) continue;
if ((x>>i&1)^(res>>i&1)) res^=b[i];
}
return res==x;
}
} B,calc;
inline ull read()
{
ull res=0;bool bo=0; char c;
while (((c=getchar())<'0'||c>'9')&&c!='-');
if (c=='-') bo=1; else res=c-48;
while ((c=getchar())>='0'&&c<='9')
res=(res<<3)+(res<<1)+(c-48);
return bo?~res+1:res;
}
void Calc(){
calc.init(cnt-1);
for (int i=0;i<=B.n;i++){
if (!B.b[i]) continue;
int x=0;
for (int j=1;j<=cnt;j++)
x|=(B.b[i]>>bit[j]&1)<<(j-1);
calc.insert(x);
}
if (!calc.check((1<<cnt)-1)) return;
int power=0,rest=k;
FT val=(FT){1,0};
for (int i=1;i<=cnt;i++) power+=bit[i]*need[i];
for (int i=0;i<=calc.n;i++)
if (calc.b[i]) power--;
for (int i=1;i<=cnt;i++) val.x*=c[rest][need[i]],rest-=need[i];
if (power>=0)
for (int i=1;i<=power;i++) val.x<<=1;
else
for (int i=1;i<=-power;i++){
if (val.x&1) val.be=true;
val.x>>=1;
}
ans=ans+val;
}
void dfs(int now,int rest){
if (now==B.n+1){
if (k==rest) Calc();
return;
}
for (int i=0;i<=k-rest;i++){
if (i) bit[++cnt]=now,need[cnt]=i;
dfs(now+1,rest+i);
if (i) --cnt;
}
}
int main(){
scanf("%d%d",&n,&k);
for (int i=1;i<=n;i++){
x=read();
for (int j=63;j>=0;j--)
if (x>>j&1) {B.n=max(B.n,j);break;}
B.insert(x);
}
for (int i=0;i<=k;i++) c[i][0]=1;
for (int i=1;i<=k;i++)
for (int j=1;j<=i;j++)
c[i][j]=c[i-1][j]+c[i-1][j-1];
dfs(0,0);
cout<<ans.x;
if (ans.be) puts(".5"); else puts("");
return 0;
}