HDU 3625

/* * 题意: 简单分析可知, 这题是求N个元素成K个以内的环, 且1不成自环的概率. * 解法: 钥匙的放置总方法数是N!. * n个元素形成k个环的方法数是第一类Stirling数s(n, k). * n个元素形成k个环, 且1成自环的总方法数是s(n-1, k-1). * 所以概率为P(N, K) = (s(n, k) - s(n-1, k-1) + s(n, k-1) - s(n-1, k-2) + ... + s(n, 1) - s(n, 0)) / N!. * Stirling数s(n, k)计算方法为: s(n, 0) = 0; s(0, 0) = 1; s(n+1, k) = s(n, k-1) - n*s(n, k). * 注意: 第一类Stirling数是带正负号的, 使用时要取绝对值. */ #include <iostream> using namespace std; const int maxn = 21; __int64 fact[maxn]; __int64 stir[maxn][maxn]; void init() { // 初始化阶乘数组 fact[0] = 1; for (int i = 1; i < maxn; i++) fact[i] = i * fact[i-1]; // 初始化Stirling数数组 for (int i = 1; i < maxn; i++) stir[i][0] = 0; stir[0][0] = 1; for (int i = 1; i < maxn; i++) for (int j = 1; j <= i; j++) stir[i][j] = stir[i-1][j-1] - (i-1) * stir[i-1][j]; // Stirling数组取绝对值 for (int i = 1; i < maxn; i++) for (int j = 1; j <= i; j++) if (stir[i][j] < 0) stir[i][j] = -stir[i][j]; } int main() { int n, k, t; __int64 sum; init(); for (scanf("%d", &t); t; t--) { scanf("%d %d", &n, &k); sum = 0; for (int i = 1; i <= k; i++) sum = sum + stir[n][i] - stir[n-1][i-1]; printf("%.4lf/n", 1.0 * sum / fact[n]); } return 0; } 

你可能感兴趣的:(HDU 3625)