[ZOJ3777] Problem Arrangement

vjudge

题意

一个排列\(\{ a_i \}\)的权值为\(\sum_{i=1}^{n}p_{i,a_i}\)
求期望随机重构排列多少次可以使这个排列的权值\(\ge m\)
\(n\le12\)

sol

假设一共有\(s\)个排列满足权值\(\ge m\),那么一次随机后满足条件的概率就是\(\frac{s}{n!}\),所以答案就是\(\frac{n!}{s}\)
考虑怎么求有多少个排列满足要求。
\(Meet\ in\ the\ middle\)。先处理前半段的所有填入方案,状态总数是\(A^{6}_{12}\)的。
然后再处理后半段的填入方案,取个补集之后就可以到前面去二分查了。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int gi()
{
	int x=0,w=1;char ch=getchar();
	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if (ch=='-') w=0,ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return w?x:-x;
}
const int N = 4100;
int s[N][721],len[N],T,n,m,p[12][12],all,ans;
void dfs1(int u,int st,int sum)
{
	if (u==n/2) {s[st][++len[st]]=sum;return;}
	for (int i=0;i<n;++i)
		if (~st&(1<<i)) dfs1(u+1,st|(1<<i),sum+p[u][i]);
}
void dfs2(int u,int st,int sum)
{
	if (u==n/2-1)
	{
		st^=all;
		ans+=len[st]+1-(lower_bound(s[st]+1,s[st]+len[st]+1,m-sum)-s[st]);
		return;
	}
	for (int i=0;i<n;++i)
		if (~st&(1<<i)) dfs2(u-1,st|(1<<i),sum+p[u][i]);
}
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int main()
{
	T=gi();
	while (T--)
	{
		n=gi();m=gi();all=(1<<n)-1;ans=0;
		for (int i=0;i<n;++i)
			for (int j=0;j<n;++j)
				p[i][j]=gi();
		memset(len,0,sizeof(len));
		dfs1(0,0,0);
		for (int i=0;i<=all;++i)
			if (len[i]) sort(s[i]+1,s[i]+len[i]+1);
		dfs2(n-1,0,0);
		if (!ans) puts("No solution");
		else {
			int fz=1;for (int i=2;i<=n;++i) fz*=i;
			int gg=gcd(fz,ans);printf("%d/%d\n",fz/gg,ans/gg);
		}
	}
	return 0;
}
posted @ 2018-04-24 16:36  租酥雨  阅读(186)  评论(0编辑  收藏  举报