题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3625
题目大意:有N个房间,每个房间里都有一把钥匙,如果要是的号码和房间的号码相同,就可以用该钥匙打开房子,最多可以破坏K个房间,一号房间只能用钥匙打开,不能被破坏,问能顺利打开全部房间的概率;
第一类斯特林数:S(N,K)=S(N-1,K-1)+(N-1)*S(N-1,k) 就是求N个元素形成K个非空循环排列的方法数,题目上说 1 号房子只能用钥匙,那么就要 S(N,K) - S(N-1,K-1),因为要减去 1 的自循环(即 1 号钥匙在 1 号房间),就是剩下的 N-1 个数形成 K-1 个环;
AC代码:
#include<cstdio>
#include<iomanip>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<math.h>
#include<map>
#include<set>
#include<queue>
#include<vector>
#include<stack>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const double pi=acos(-1.0);
const ll mod=1000;
const int N=25;
const int M=100000;
ll a[N][N];
ll f[N];
void work()
{
f[0]=1;
f[1]=1;
for(int i=2;i<=20;i++)
f[i]=f[i-1]*i;
for(int i=1;i<=20;i++)
{
a[i][i]=1;
for(int j=1;j<i;j++)
a[i][j]=a[i-1][j-1]+a[i-1][j]*(i-1);
}
}
int main()
{
work();
int T;
for(scanf("%d",&T);T--;)
{
int n,k;
ll ans=0;
scanf("%d %d",&n,&k);
for(int i=1;i<=k;i++)
ans+=a[n][i]-a[n-1][i-1];
printf("%.4lf\n",(double)ans/f[n]);
}
return 0;
}