[清华集训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;
}
posted @ 2019-05-12 20:55  WR_Eternity  阅读(137)  评论(0编辑  收藏  举报