斯特灵数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 ;
}
每次做题提醒自己:题目到底有没有读懂,有没有分析彻底、算法够不够贪心、暴力够不够优雅。