题意
一个排列({ a_i })的权值为(sum_{i=1}^{n}p_{i,a_i})。
求期望随机重构排列多少次可以使这个排列的权值(ge m)。
(nle12)
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
",fz/gg,ans/gg);
}
}
return 0;
}