斯特林数的第一类应用
题意就是 求n个元素分成k个环排列的数目。
递推公式是:
s( n , 0 ) = 0;
s( 1 ,1 ) =1;
s( n , k ) = s( n- 1 , k-1 )+ (n-1)*s( n-1 , k);
公式的意思是 :
当 n-1个 形成了 k-1 个 环时,第n个只能形成单环。 方案数 是 s( n -1 , k -1 )
当n-1个形成了 k个环时,这 k 个环中 共有 n-1 个位置可以放, 则 方案数 是 s( n-1 , k ) *( n -1);
此题中 第一个门 只能用钥匙 , 也就是说 1 不可以形成单环。 则 n 个元素形成 k 个环的 方案数 是 s(n, k) - s( n -1 , k-1);
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define LL long long
LL s[25][25];
void init(){
memset(s,0,sizeof(s));
s[1][1] = 1;
for(int i=2;i<=20;i++){
for(int k =1;k<=i;k++){
s[i][k] = s[i-1][k-1] + (i-1)*s[i-1][k];
// cout << s[i][k] << " ";
}
// cout << endl;
}
}
int n, k ;
void solve(){
LL sum =0 ;
for(int i=1;i<=k;i++){
sum += s[n][i];
}
for(int i =1;i<= k-1;i++){
sum -= s[n-1][i];
}
LL p = 1;
for(int i=1;i<=n;i++){
p *= i;
}
double ans = sum / (double)p;
printf("%.4f\n",ans);
}
int main() {
int t ;
cin >> t;
init();
while(t-- ){
scanf("%d%d",&n,&k);
solve();
}
return 0;
}