hihoCoder - 1075 开锁魔法III
Posted aziint
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hihoCoder - 1075 开锁魔法III相关的知识,希望对你有一定的参考价值。
Description
一日,崔克茜来到小马镇表演魔法。
其中有一个节目是开锁咒:舞台上有 (n(nle 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
", f[cnt][K] / c[n][K]);
}
return 0;
}
以上是关于hihoCoder - 1075 开锁魔法III的主要内容,如果未能解决你的问题,请参考以下文章
Hihocoder #1075 : 开锁魔法III (组合数学+动态规划)
Little Pony and Alohomora Part 3 [HihoCoder 1075]
bzoj5003: 与链 5004: 开锁魔法II 5005:乒乓游戏
带权并查集(含种类并查集)经典模板 例题:①POJ 1182 食物链(经典)②HDU - 1829 A bug's life(简单) ③hihoCoder 1515 : 分数调查(示例代码(代