在哈理工校赛 见到了一道题

 一日,崔克茜来到小马镇表演魔法。
其中有一个节目是开锁咒:舞台上有 n 个盒子,每个盒子中有一把钥匙,对于每个盒子而言有且仅有一把钥匙能打开它。崔克茜可以通过魔法,暴力打开一个盒子。崔克茜想知道,期望使用多少次魔法可以打开所有盒子,你能帮助她回答吗?

隐隐约约是要求排列中的环,后来得到一个公式 a (n) = a (n - 1)* n + (n - 1)!

                                      然后费尽心思 求出了通项公式  a (n) / n!  =  a (n - 1) / (n - 1) ! + 1 / n

                                                                              a (n) / n!  - a (n - 1) / (n - 1) ! = 1 / n

                                                                                a (2) / 2 ! - a (1) / 1 ! = 1/ 1

                                                                                 .

                             .

                             .

                             累加可得 a (n) = n!* (1 / 1 + 1 / 2 + 1 / 3 + ....  1 / n)

 

 

后来做到hdu 3625时 才知道这个是著名的斯特林数 

题目:

就是给你N个房间,然后每个房间1把钥匙,你最初手里没有任何钥匙,要靠破门而入!这里只有第一个房间不能破门进去,其他都可以,

给你房间数N,和最多能破门的个数,让你求能全部把房间打开的概率!

题目分析:

首先这题其实让我们求的是给 N个元素,让我们求K个环排列的 方法数。

斯特林第一类数的第推公式:

S(N,0)=0;

S(N,N)=1;

S(0,0)=0;

S(N,K)=S(N-1,K-1)+S(N-1,K)*(N-1);

这个公式的意思是:

当前N-1个数构成K-1 个环的时候,加入第N个 ,N只能构成单环!---S(N-1,K-1)

如果N-1个数构成K个环的时候,加入第N个,N可以任意加入,N-1内的一个环里,所以是--(N-1)*S(N-1,K)

这个题目里,因为不能破坏第1个门:

所以

所以还要减去N-1个房间被最多K-1把钥匙打开的情况数

S(N,K)-S(N-1,K-1)

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <queue>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <vector>
 7 #include <string>
 8 #include <iterator>
 9 #include <cmath>
10 #include <deque>
11 #include <stack>
12 #include <cctype>
13 using namespace std;
14 
15 const int N = 21;
16 const int INF = 0xfffffff;
17 
18 typedef long long ll;
19 typedef long double ld;
20 
21 #define INFL 0x7fffffffffffffffLL
22 #define met(a, b) memset(a, b, sizeof(a))
23 #define rep(c, a, b) for (int c = a; c < b; c++)
24 #define nre(c, a, b) for (int c = a; c > b; c--)
25 
26 ll str[N][N];
27 ll cat (int n);
28 void init ();
29 
30 int main ()
31 {
32    int t; init ();
33    cin >> t;
34    while (t--)
35    {
36        int n, k;
37        cin >> n >> k;
38        if (n == 1 || k == 0) {cout << "0.0000" << endl; continue;}
39        ll sum = 0;
40        for (int i=1; i<=k; i++)
41         sum += str[n][i] - str[n-1][i-1];
42        printf("%.4f\n", 1.0 * sum / cat(n));
43    }
44    return 0;
45 }
46 
47 ll cat (int n)
48 {
49     ll ans = 1;
50     for (int i=1; i<=n; i++)
51         ans *= i;
52     return ans;
53 }
54 
55 void init ()
56 {
57     for (int i=1; i<21; i++)
58     {
59         str[i][0] = 0, str[i][i] = 1;
60         for (int j=1; j<i; j++)
61             str[i][j] = str[i-1][j-1] + (i-1) * str[i-1][j];
62     }
63 }
View Code

 

posted on 2015-03-31 16:51  白夜叉降临  阅读(194)  评论(0编辑  收藏  举报