hdu 3625

Posted 2018slgys

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu 3625相关的知识,希望对你有一定的参考价值。

技术图片

题目链接

hdu 5625

题目概述

????????每个仓库里面存放了一把钥匙(可能是打开这个仓库的,也可能是打假设最多可以强制打开(k)个仓库然后取到里面的钥匙,并且要求不能强制打开1号仓库,那么计算可以把所有仓库都打开的概率,保留4位小数.

一点想法

????????首先考虑这样一个问题,就是(n)个仓库,如何能够打开(k)个仓库,拿到里面的钥匙,然后可以打开剩下其它的仓库的,很明显这个是当这(n)个仓库组成(k)个圆排列,然后从每个圆排列中暴力打开一个,取得钥匙,然后这个圆排列上的仓库都可以打开(此时每一个仓库放置的是它下一个仓库的钥匙),这个对应的就是第一类Stirling数.但是这个题目有一个要求,不能暴力打开1号仓库,所以1号仓库的钥匙只能这样放置,从(n-1)个仓库组成的(k)个排列中随机选择一个仓库放置1号钥匙,都可以通过先打开其他的仓库然后获得1号仓库的钥匙;但是对于(n-1)个仓库已经排成(k-1)个排列的情况,此时1号必须把它的钥匙放置到自身,但是自身又不能暴力打开,所以对于(n)个仓库不能暴力打开1号,至多先暴力打开(k)个仓库获得钥匙然后打开其他仓库以便全部打开的要求,在已经计算出的第一类(Stirling)s数(s(n,k))上,要减去1号放置自身的情况,也就是(s(n,k)-s(n-1,k-1)).

????????上面计算的是能够打开并且保证1号不被暴力打开的可能方法数,随机放置钥匙的总的方法数是(n!),所以要计算概率,只要将可行的方法数除以总数就可以了,因为题目中要求的是至多打开(k)次,所以意味着使用(1,2,dots,k-1)也要算作到至多(k)次里面.

注意

????????我当时算第一类(Stirling)数的时候考虑到了不能算完一项后就直接减,因为递推式的计算依赖于前面两项,所以我就在算完整个后去减前面的项.是的,没错,就是那么憨-_-||,忘记了递推式后面的依赖于前面的,所言前面几个因为是0计算没改变,但是一旦遇到非0的,那么前面的结果就开始改变,对应后面的也开始改变,于是越变越离谱,交上去总是WA┭┮﹏┭┮.

代码实现

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 30;
ll s[N][N];
ll ans[N][N];
ll f[N];

void calculate(){
    s[0][0] = 1;
    f[0] = 1;
    // 计算第一类Stirling数
    for (int i = 1; i < N; i++){
        for (int j = 0; j <= i; j++){
            // 第一类Stirling数递推式
            s[i][j] = (i-1) * s[i - 1][j] + s[i-1][j-1];
        }
        f[i] = f[i - 1] * i;
    }
    // 不能这样剔除,前面的改变后会影响后面剔除的结果。
    // for (int i = 1; i < N; i++){
    //     for (int j = 1; j <= i; j++){
    //         // 剔除没法打开1的情况
    //         s[i][j] -= s[i-1][j-1];
    //     }
    // }
    for (int i = 0; i < N; i++){
        for (int j = 1; j <= i; j++){
            ans[i][j] = ans[i][j - 1] + s[i][j] - s[i-1][j-1];
        }
    }
}

void print(){
    for(int i = 0; i < N; i++){
        for(int j = 0; j <= i; j++){
            printf("%lld ", s[i][j]);
        }
        printf("
");
    }
}
int main(int argc, const char** argv) {
    calculate();
    // print();
    int t;
    scanf("%d", &t);
    while (t--){
        int n, m;
        scanf("%d%d", &n, &m);
        printf("%.4f
", 1.0 * ans[n][m] / f[n]);
    }
    return 0;
}

补充

以上是关于hdu 3625的主要内容,如果未能解决你的问题,请参考以下文章

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

HDU 3625 Examining the Rooms

hdu 3625

hdu 3625 Examining the Rooms —— 第一类斯特林数

HDU 3625 Examining the Rooms:第一类stirling数

HDU 3625 Examining the Rooms