斯特灵数stirling

第一次接触srirling ,对于之前的我来说就是传说中的斯特灵数,
推荐一篇还不错的讲解stirling的数

hdu 3625
在酒店发生了谋杀案。作为镇上最好的侦探,你应该立即检查酒店的所有N个房间。然而,房间的所有门都是锁着的,钥匙只是锁在房间里,这是一个陷阱!您知道每个房间只有一个密钥,并且所有可能的分布都具有相同的可能性。例如,如果N = 3,则有6种可能的分布,每种分布的可能性为1/6。为方便起见,我们将房间从1到N编号,房间1的钥匙编号为Key 1,房间2的钥匙为Key 2等。
要检查所有房间,你必须用武力摧毁一些门。但是你不想破坏太多,所以你采取以下策略:首先,你手上没有钥匙,所以你随机摧毁一扇锁着的门,进入房间,检查它并取出钥匙。然后也许你可以用新钥匙打开另一个房间,检查它并获得第二把钥匙。重复此操作,直到您无法打开任何新房间。如果仍有未经检查的房间,您必须随机选择另一个未开启的门以强行销毁,然后重复上述步骤,直到检查完所有房间。
现在你只能用力摧毁最多K个门。更重要的是,在房间1里住着一个非常重要的人。你不能破坏房间1的门,也就是说,检查房间1的唯一方法是用相应的钥匙打开它。您想知道最终可以检查所有房间的可能性。

题目意思也就相当于组成最多组成k个圈圈,其中1有点特殊,他不能单独成环,
这也就是第一类stirling
所以就是s[n][i] - s[n - 1][i - 1] 也就是在总的基础上面减掉了单独成环的一个方面

#include <iostream>
#include <cstdio>
using namespace std;

typedef long long ll ;
ll f[25] , s[25][25];
int main()
{
	f[0] = 1 ;
	for(int i = 1;i <= 21;i ++)
	 f[i] = f[i - 1] * i ;
	for(int i = 1;i <= 21;i ++)
	 {
	 	s[i][0] = 0 , s[i][i] = 1 ;
		 for(int j = 1;j <= 21;j ++) 
		  if(i != j)  s[i][j] = s[i - 1][j - 1] + (i - 1) * s[i - 1][j] ; 
	 } 
	int t ;
	cin >> t ;
	while(t --)
	{
		int n , k ;
		cin >> n >> k ;
		ll ans = 0 ;
		for(int i = 1;i <= k;i ++)
		 ans += s[n][i] - s[n - 1][i - 1] ;
//		cout << ans << endl ;
		printf("%.4lf\n",(double)ans/f[n]);
	}
	return 0 ;
 } 
posted @ 2019-08-20 01:52  spnooyseed  阅读(150)  评论(0编辑  收藏  举报