码迷,mamicode.com
首页 > 其他好文 > 详细

UOJ#36. 【清华集训2014】玛里苟斯 线性基

时间:2019-02-08 17:08:20      阅读:185      评论:0      收藏:0      [点我收藏+]

标签:参考   ++   相等   ini   break   pre   .com   getch   pac   

原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ36.html

题解

按照 $k$ 分类讨论:

k=1 : 我们考虑每一位的贡献。若有至少一个数第 $i$ 位为 $1$ ,则对答案的贡献为 $2^i/2$ 。

k=2 : 发现每个异或和的平方为 $\sum_i\sum_j2^{i+j}bit_ibit_j$。那么考虑第 $i$ 位和第 $j$ 位的积的期望值。如果所有的数中,第 $i$ 位和第 $j$ 位均相等且非全零,那么参考 k=1 的情况,期望为 1/2;否则,第 $i$ 位为 $1$ 的概率为 1/2,第 $j$ 位为 $1$ 的概率为 1/2,$i×j$ 为 $1$ 的概率为 0.25 。
$k\leq 3$ : 由于答案不超过 $2^{63}$ ,直接把线性基搞出来之后暴力枚举就好了。

代码

#include <bits/stdc++.h>
#define clr(x) memset(x,0,sizeof (x))
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
LL read(){
	LL x=0,f=0;
	char ch=getchar();
	while (!isdigit(ch))
		f|=ch==‘-‘,ch=getchar();
	while (isdigit(ch))
		x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return f?-x:x;
}
const int N=100005;
int n,k;
ULL a[N];
void init(){
	static ULL x[64];
	clr(x);
	n=read(),k=read();
	for (int i=1;i<=n;i++){
		ULL v=read();
		for (int i=63;~i;i--)
			if (v>>i&1ULL)
				if (!x[i]){
					x[i]=v;
					break;
				}
				else
					v^=x[i];
	}
	n=0;
	for (int i=63;~i;i--)
		if (x[i])
			a[++n]=x[i];
}
void Out(ULL x){
	cout<<x/2;
	if (x&1LLU)
		cout<<".5";
}
namespace k1{
	void solve(){
		ULL ans=0;
		for (int i=1;i<=n;i++)
			ans|=a[i];
		Out(ans);
	}
}
namespace k2{
	void solve(){
		ULL ans=0;
		for (int i=0;i<33;i++)
			for (int j=0;j<33;j++){
				int f1=0,f2=0,f=0;
				for (int t=1;t<=n;t++){
					f1|=a[t]>>i&1ULL;
					f2|=a[t]>>j&1ULL;
					f|=(a[t]>>i&1ULL)!=(a[t]>>j&1ULL);
				}
				if (!f1||!f2)
					continue;
				ans+=1ULL<<(i+j-f);
			}
		Out(ans);
	}
}
namespace k3{
	__int128 tot;
	__int128 Pow(__int128 x,int y){
		__int128 ans=1;
		for (;y;y>>=1,x*=x)
			if (y&1)
				ans*=x;
		return ans;
	}
	void solve(){
		tot=0;
		for (int i=(1<<n)-1;i>=0;i--){
			ULL tmp=0;
			for (int j=0;j<n;j++)
				if (i>>j&1)
					tmp^=a[j+1];
			tot+=Pow(tmp,k);
		}
		while (tot%2==0&&n>1)
			n--,tot/=2;
		cout<<(ULL)tot/2;
		if (tot%2==1)
			cout<<".5";
	}
}
int main(){
	init();
	if (k==1)
		k1::solve();
	else if (k==2)
		k2::solve();
	else
		k3::solve();
	return 0;
}

  

UOJ#36. 【清华集训2014】玛里苟斯 线性基

标签:参考   ++   相等   ini   break   pre   .com   getch   pac   

原文地址:https://www.cnblogs.com/zhouzhendong/p/UOJ36.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!