hdu 3625 Examining the Rooms 轮换斯特林数
题目大意
n个房间对应n把钥匙
每个房间的钥匙随机放在某个房间内,概率相同。
有K次炸门的机会,求能进入所有房间的概率
一号门不给你炸
分析
我们设\(key_i\)为第i间房里的钥匙是哪把
视作房间i向房间\(key_i\)连了一条有向边
这相当于n个点n条边,且每个点出度入度都为1
就是m个环,就是置换嘛
相当于第一类斯特林数\(\left [\begin{matrix} n\\ m \end{matrix}\right]\)
做法
一个环中炸掉一个门就可以开环中所有的门
问题转化为求环的数量\(\le k\)的方案数
由于1不能单独在一个环中(因为不能炸)
\[\sum\limits_{k=1}^n\left( \left [\begin{matrix} n\\ k \end{matrix}\right]-\left [\begin{matrix} n-1\\ k-1 \end{matrix}\right] \right)
\]
(1单独在一个环中则剩下n-1个点和k-1个环)
solution
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef double db;
const int M=23;
int rd(){
int x=0;bool f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
for(;isdigit(c);c=getchar()) x=x*10+c-48;
return f?x:-x;
}
int tcas;
int n,m;
LL lh[M][M];
LL fac[M];
void init(){
int i,j;
lh[0][0]=1;
for(i=1;i<=20;i++)
for(j=1;j<=i;j++)
lh[i][j]=(i-1)*lh[i-1][j]+lh[i-1][j-1];
for(fac[0]=1,i=1;i<=20;i++) fac[i]=fac[i-1]*i;
}
int main(){
init();
int i;
tcas=rd();
while(tcas--){
n=rd(),m=rd();
LL ans=0;
for(i=1;i<=m;i++)
ans+=lh[n][i]-lh[n-1][i-1];
printf("%.4lf\n",(db)ans/fac[n]);
}
return 0;
}