[HDU 3625] Examining the Rooms(第一类斯特林数)

Examining the Rooms

problem

hdu 3625

solution

之前考试有一道题:最多砸开 k k k 扇门,采取最有操作,求把 n n n 个门都打开的方案数。

本题稍稍多了一个不能砸开第一扇门的限制,以及求的是概率。

概率好说,可行方案数除以总方案数即可,总方案数显然是 n n n 把钥匙随便放的全排列, n ! n! n!

先不考虑不能砸开第一扇门,即暴力开启最多 k k k 扇门就能开启所有门。

注意到一扇门打开后只放着一把钥匙,如果不是暴力开启的门的钥匙,那么一定会开启另一扇门。

这可以对应到图上的一条边,而最后暴力开启门的钥匙就将这个形状连成一个环。

且环环之间相互独立。【只有一把钥匙一扇门】

这就相当于是将 n n n 扇门划分成最多 k k k 个圆排列的方案数。

熟悉的同学立马反应过来这就是第一类斯特林数的定义。

s ( n , k ) = s ( n − 1 , k − 1 ) + s ( n − 1 , k ) ∗ ( n − 1 ) s(n,k)=s(n-1,k-1)+s(n-1,k)*(n-1) s(n,k)=s(n1,k1)+s(n1,k)(n1)

s ( n − 1 , k − 1 ) → n s(n-1,k-1)\rightarrow n s(n1,k1)n 自己单独新增一个圆排列。

s ( n − 1 , k ) ∗ ( n − 1 ) s(n-1,k)*(n-1) s(n1,k)(n1) n n n 放到前面 k k k 个原排列中的某一个中去。

相当于是断开一条边, u → v ⇒ u → n → v u\rightarrow v\Rightarrow u\rightarrow n\rightarrow v uvunv n n n 放任意一个位置都对应着不同的圆排列,即不同的钥匙方案数。

一共可以放 n − 1 n-1 n1 个位置,方案数就要 × ( n − 1 ) \times (n-1) ×(n1)

现在加上不能暴力打开第一扇门的限制。

这个限制其实就是限制不能让第一扇门单独成为一个大小为 1 1 1 的圆排列。

如果是 n n n 个划分成 k k k 个圆排列,就得是 s ( n , k ) − s ( n − 1 , k − 1 ) s(n,k)-s(n-1,k-1) s(n,k)s(n1,k1)

求前缀和最后除以阶乘即是所求。

code

#include <bits/stdc++.h>
using namespace std;
#define maxn 25
#define int long long
int T, n, k;
int fac[maxn];
int dp[maxn][maxn];
signed main() {
    dp[0][0] = fac[0] = 1;
    for( int i = 1; i < maxn;i ++ )
        for( int j = 1; j < maxn;j ++ )
            dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j] * ( i - 1 );
    for( int i = 1; i < maxn;i ++ ) fac[i] = fac[i - 1] * i;
    scanf( "%lld", &T );
    while( T -- ) {
        scanf( "%lld %lld", &n, &k );
        int ans = 0;
        for( int i = 0; i <= k;i ++ ) ans += dp[n][i];
        for( int i = 0;i < k;i ++ ) ans -= dp[n - 1][i];
        printf( "%.4f\n", 1.0 * ans / fac[n] );
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值