i
向
那么把钥匙分配给这些环的概率就是答案
DP
fi,j
表示前
i
个环都打开了,还剩下
fi,j=fi−1,k×(sizeik−j)(n−sizeij)(nk)
这样DP是 O(n2) 的
不过BZOJ没有spj,被卡精度了…hihocoder上过了…
DP转移可以改一下
fi,j=fi−1,k×(sizeik−j)
这样求出总方案数,最后除以 (nk) 就好了…
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=310;
int T,t,n,k,size[N],vis[N],a[N];
double f[N][N],C[N][N];
int dfs(int x){
if(vis[x]) return 0;
vis[x]=1; return dfs(a[x])+1;
}
int main(){
scanf("%d",&T);
C[1][1]=1; C[0][0]=1;
for(int i=1;i<=300;i++) C[i][0]=1;
for(int i=2;i<=300;i++)
for(int j=1;j<=i;j++)
C[i][j]=C[i-1][j]+C[i-1][j-1];
while(T--){
scanf("%d%d",&n,&k); int nn=n;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) vis[i]=size[i]=0;
t=0;
for(int i=1;i<=n;i++){
if(vis[i]) continue;
t++; size[t]=dfs(i);
}
for(int i=0;i<=n;i++)
for(int j=0;j<=k;j++) f[i][j]=0;
f[0][k]=1;
for(int i=1;i<=t;i++){
for(int j=1;j<=k;j++){
if(f[i-1][j]<1e-7) continue;
for(int s=1;s<=size[i] && s<=j;s++)
f[i][j-s]+=f[i-1][j]*C[size[i]][s];
}
n-=size[i];
}
printf("%.9lf\n",f[t][0]/C[nn][k]);
}
return 0;
}