hdu 3265 第一类斯特林数

先和第二类做一个对比

第一类Stirling数是有正负的,其绝对值是包含n个元素的集合分作k个环排列的方法数目。
递推公式为, S(n,0) = 0, S(1,1) = 1.   S(n+1,k) = S(n,k-1) + nS(n,k)。 
边界条件: S(0 , 0) = 1 S(p , 0) = 0 p>=1 S(p , p) =1 p>=0 
一些性质: S(p ,1) = 1 p>=1 S(p, 2) = 2^(p-1)– 1 p>=2   


第二类Stirling数是把包含n个元素的集合划分为正好k个非空子集的方法的数目。   
递推公式为:   S(n,k)=0; (n<k||k=0)   S(n,n) = S(n,1) = 1,   
S(n,k) = S(n-1,k-1) + kS(n-1,k).
考虑第p个物品,p可以单独构成一个非空集合,此时前p-1个物品构成k-1个非空的
不可辨别的集合,方法数为S(p-1,k-1);
也可以前p-1种物品构成k个非空的不可辨别的集合,
第p个物品放入任意一个中,这样有k*S(p-1,k)种方法。

然后说下这道题目,题目说每个房间都锁死了,切钥匙都在房间里面。我们可以任意的强行开一个门(除了1号门),然后拿到钥匙去开其他门,重复这个操作,如果开不了门,我们在强行开一个,依次类推。题目要求最多只允许强开k扇门的时候,有多大的几率把所有的门都打开。模拟一下发现和第一类斯特林数差不多,就是要特殊处理一下第一个门不能强开的情况。

ac代码:

#include <iostream>  
#include <stdio.h>  
#include <string>  
#include <string.h>  
#include <algorithm>  
using namespace std;  
typedef long long ll;  
ll stir[22][22];  
ll jie[22];  
  
void init()  
{  
  stir[1][0]=0;  
  stir[1][1]=1;  
  for(int i=2;i<=20;i++)  
     for(int j=1;j<=i;j++)  
        stir[i][j]=stir[i-1][j-1]+(i-1)*stir[i-1][j];  
  jie[1]=1;  
  for(int i=2;i<=20;i++)jie[i]=jie[i-1]*i;  
}  
  
int main()  
{  
   int T;  
   scanf("%d",&T);  
   init();  
   while(T--)  
   {  
      int n,k;  
      scanf("%d%d",&n,&k);  
      ll ans=0;  
      for(int i=1;i<=k;i++)  
            ans+=stir[n][i]-stir[n-1][i-1];  
      printf("%.4lf\n",ans*1.0/jie[n]);  
   }  
   return 0;  
}  

 

posted @ 2017-10-11 15:34  猪突猛进!!!  阅读(393)  评论(0编辑  收藏  举报