码迷,mamicode.com
首页 > 其他好文 > 详细

hihoCoder - 1075 开锁魔法III

时间:2018-08-13 16:57:17      阅读:149      评论:0      收藏:0      [点我收藏+]

标签:小马   flag   简单   class   std   lag   cpp   int   namespace   

Description

一日,崔克茜来到小马镇表演魔法。

其中有一个节目是开锁咒:舞台上有 \(n(n\le 300)\) 个盒子,每个盒子中有一把钥匙,对于每个盒子而言有且仅有一把钥匙能打开它。初始时,崔克茜将会随机地选择 \(k\) 个盒子用魔法将它们打开。崔克茜想知道最后所有盒子都被打开的概率,你能帮助她回答这个问题吗?

Solution

这 gay 题。

\(i\) 连向 \(a_i\) ,就成了若干简单环。只要最开始打开一个环内任何一个点,就可以打开整个环。

令每个环大小为 \(size[i]\) ,数量为 \(cnt\) ,那么问题就变成了,\(cnt\) 堆物品,每堆有 \(size[i]\) 个,选出 \(k\) 个,求每一堆都至少有一个被选出的概率。

然后就可以 dp 了。\(dp[i][j]\) 表示前 \(i\) 堆,选了 \(j\) 个。转移见代码。

#include<bits/stdc++.h>
using namespace std;

template <class T> void read(T &x) {
    x = 0; bool flag = 0; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == 45) flag = 1;
    for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48; if (flag) x = -x;
}

#define N 301
#define rep(i, a, b) for (int i = (a); i <= (b); i++ )

int a[N], siz[N];
double f[N][N], c[N][N];
bool vis[N];

int main() {
    int T; read(T);
    rep(i, 0, 300) {
        c[i][0] = c[i][i] = 1;
        rep(j, 1, i - 1) c[i][j] = c[i - 1][j] + c[i - 1][j - 1];
    }
    while (T--) {
        int n, K, cnt = 0; read(n), read(K);
        rep(i, 1, n) read(a[i]);
        memset(vis, 0, sizeof vis);
        rep(i, 1, n) if (!vis[i]) {
            int j = i, sum = 0;
            while (!vis[j]) sum++, vis[j] = 1, j = a[j];
            siz[cnt++] = sum;
        }
        memset(f, 0, sizeof f), f[0][0] = 1;
        rep(i, 0, cnt - 1) rep(j, 0, K) if (fabs(f[i][j]) > 1e-8) rep(k, 1, min(siz[i], K - j))
            f[i + 1][j + k] += f[i][j] * c[siz[i]][k];
        printf("%.5lf\n", f[cnt][K] / c[n][K]);
    }
    return 0;
}

hihoCoder - 1075 开锁魔法III

标签:小马   flag   简单   class   std   lag   cpp   int   namespace   

原文地址:https://www.cnblogs.com/aziint/p/9468880.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!