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;
}
posted @ 2017-02-25 18:48  _zwl  阅读(202)  评论(0编辑  收藏  举报