【BZOJ3811】【清华集训2015】玛里苟斯(线性基)

传送门


解析:

还是挺好想的,首先对于k=1的情况,如果某一个数在这一位上有1,那么最终结果中这一位为1的概率就是0.5。

有一个很显然的性质,所有异或结果出现概率(或者说方案数)相同。

其次,对于k=2的情况,线性基上高消,然后直接考虑每个二元组就行了。

对于剩下的,由于保证答案不超过 2 63 2^{63} 263,所以数本身不超过 2 21 2^{21} 221,直接暴力干就行了。


代码:

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned ll
#define re register
#define gc get_char
#define cs const

namespace IO{
	inline char get_char(){
		static cs int Rlen=1<<22|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;		
	}
	
	template<typename T>
	inline T get(){
		re char c;
		while(!isdigit(c=gc()));re T num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
	inline int getint(){return get<int>();}
	inline ull getull(){return get<ull>();}
}
using namespace IO;

using std::cerr;
using std::cout;

ull base[100],a[100005];
inline void ins(ull a){
	for(int re i=0;i<=63;++i)if((1ull<<i)&a){
		if(!base[i]){
			base[i]=a;
			return ;
		}
		a^=base[i];
	}
} 

int n,m,k;
ull ans1,ans2;

inline void dfs(int step,ull state){
	if(step>m){
		ll sum1=0,sum2=1;
		for(int re i=1;i<=k;++i){
			sum1*=state,sum2*=state;
			sum1+=(sum2>>m);
			sum2&=(1<<m)-1;
		}
		ans1+=sum1,ans2+=sum2;
		ans1+=(ans2>>m);
		ans2&=(1<<m)-1;
		return ;
	}
	dfs(step+1,state);
	dfs(step+1,state^base[step]);
}

signed main(){
	n=getint(),k=getint();
	if(k==1){
		ull ans=0;
		for(int re i=1;i<=n;++i)ans|=getull();
		printf(ans&1?"%llu.5":"%llu",ans>>1);
		return 0;
	}
	if(k==2){
		m=1;
		for(int re i=1;i<=n;++i)base[1]|=a[i]=getull();
		for(int re i=1;i<=n;++i)
		for(int re j=1;j<=m;++j){
			if(!(base[j]&~a[i])||!(base[j]&a[i]))continue;
			base[++m]=base[j]&a[i];base[j]&=~a[i];
		}
		ull ans=0;
		for(int re i=1;i<=m;++i)
		for(int re j=i;j<=m;++j)ans+=base[i]*base[j];
		printf(ans&1?"%llu.5":"%llu",ans>>1);
		return 0;
	}
	for(int re i=1;i<=n;++i)ins(getull());
	m=0;
	for(int re i=0;i<64;++i)if(base[i])base[m++]=base[i];
	for(int re i=m;i;--i)base[i]=base[i-1];
	dfs(1,0);
	printf(ans2?"%llu.5":"%llu",ans1);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值