【bzoj5004】开锁魔法II 组合数学+概率dp
有 $n$ 个箱子,每个箱子里有且仅有一把钥匙,每个箱子有且仅有一把钥匙可以将其打开。现在随机打开 $m$ 个箱子,求能够将所有箱子打开的概率。
题解
组合数学+概率dp
题目约定了每个点的入度和出度均为1,因此最终的图一定是若干个环。每个环都至少选择一个点即可满足要求。
预处理出每个环的点数 $c[i]$ 以及其后缀和 $sum[i]$ 。
设 $f[i][j]$ 表示前 $i$ 个环中选出 $j$ 个点,满足最终条件的概率。初始化 $f[0][0]=1$ 。
枚举 $i$ 和前 $i-1$ 个环的点数 $j$ 、第 $i$ 个环的点数 $k$ ,那么:$i\sim n$ 的总方案数为 $C_{sum[i]}^{m-j}$ ,满足条件的方案数为 $c[i]$ 中选出 $k$ 个的方案数乘以剩下部分选出 $m-j-k$ 个的方案数 $C_{c[i]}^k·C_{sum[i]-c[i]}^{m-j-k}$ 。
整理一下即可得到dp方程 $f[i][j+k]\leftarrow f[i-1][j]·\frac{C_{c[i]}^k·C_{sum[i]-c[i]}^{m-j-k}}{C_{sum[i]}^{m-j}}$ 。
最后的答案就是 $f[n][m]$ 。
其中组合数直接使用double存据说能过,然而我比较怂,因此存的是阶乘的 $\ln$ ,求的时候再 $\text{exp}$ 回去。
时间复杂度 $O(Tn^2)$
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 310
using namespace std;
int a[N] , c[N] , vis[N] , sum[N];
double fac[N] , f[N][N];
int main()
{
int T;
scanf("%d" , &T);
while(T -- )
{
memset(vis , 0 , sizeof(vis));
memset(f , 0 , sizeof(f));
f[0][0] = 1;
int n , m = 0 , p , i , j , k;
scanf("%d%d" , &n , &p);
for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &a[i]) , fac[i] = fac[i - 1] + log(i);
for(i = 1 ; i <= n ; i ++ )
{
if(!vis[i])
{
c[++m] = 0;
for(j = i ; !vis[j] ; j = a[j])
vis[j] = 1 , c[m] ++ ;
}
}
sum[m + 1] = 0;
for(i = m ; i ; i -- ) sum[i] = sum[i + 1] + c[i];
for(i = 1 ; i <= m ; i ++ )
for(j = max(i - 1 , p - sum[i]) ; j < p && j <= n - sum[i] ; j ++ )
for(k = 1 ; k <= c[i] && j + k <= p ; k ++ )
f[i][j + k] += f[i - 1][j] * exp(fac[c[i]] + fac[sum[i] - c[i]] + fac[p - j] + fac[sum[i] - p + j] - fac[k] - fac[c[i] - k] - fac[p - j - k] - fac[sum[i] - c[i] - p + j + k] - fac[sum[i]]);
printf("%.9lf\n" , f[m][p]);
}
return 0;
}
【bzoj5004】开锁魔法II 组合数学+概率dp的更多相关文章
- HihoCoder 1075 开锁魔法III(概率DP+组合)
描述 一日,崔克茜来到小马镇表演魔法. 其中有一个节目是开锁咒:舞台上有 n 个盒子,每个盒子中有一把钥匙,对于每个盒子而言有且仅有一把钥匙能打开它.初始时,崔克茜将会随机地选择 k 个盒子用魔法将它 ...
- BZOJ 5004: 开锁魔法II 期望 + 组合
Description 题面:www.lydsy.com/JudgeOnline/upload/task.pdf Input Output 一般概率题有两种套路: 满足条件的方案/总方案. 直接求概率 ...
- bzoj5003: 与链 5004: 开锁魔法II 5005:乒乓游戏
www.lydsy.com/JudgeOnline/upload/task.pdf 第一题题意可以转为选一个长度k的序列,每一项二进制的1的位置被下一项包含,且总和为1,考虑每个二进制位的出现位置,可 ...
- BZOJ 5004: 开锁魔法II
比较显然 #include<cstdio> #include<algorithm> #include<cstring> using namespace std; i ...
- hihocoder1075【开锁魔法】
hihocoder1075[开锁魔法] 题意是给你一个 \(1-n\) 的置换,求选 \(k\) 个可以遍历所有点的概率. 题目可以换个模型:有 \(n\) 个球,有 \(cnt\) 种不同的颜色,求 ...
- hrb——开锁魔法I——————【规律】
解题思路:从1到n的倒数之和. #include<stdio.h> #include<string.h> #include<algorithm> using nam ...
- hihocoder 1075 : 开锁魔法III
描述 一日,崔克茜来到小马镇表演魔法. 其中有一个节目是开锁咒:舞台上有 n 个盒子,每个盒子中有一把钥匙,对于每个盒子而言有且仅有一把钥匙能打开它.初始时,崔克茜将会随机地选择 k 个盒子用魔法将它 ...
- #1075 : 开锁魔法III
描述 一日,崔克茜来到小马镇表演魔法. 其中有一个节目是开锁咒:舞台上有 n 个盒子,每个盒子中有一把钥匙,对于每个盒子而言有且仅有一把钥匙能打开它.初始时,崔克茜将会随机地选择 k 个盒子用魔法将它 ...
- Hiho #1075: 开锁魔法III
Problem Statement 描述 一日,崔克茜来到小马镇表演魔法. 其中有一个节目是开锁咒:舞台上有 n 个盒子,每个盒子中有一把钥匙,对于每个盒子而言有且仅有一把钥匙能打开它.初始时,崔克茜 ...
随机推荐
- CSS中的before和:after伪元素深入理解
1.定义: “伪元素”,顾名思义.就是它创建了一个虚假的元素,并且将其虚假的元素插入到目标元素的内容之前或之后. 2:特点: a.它在实际文档中不改变什么,但是对用户可见,可以通过css控制,源码中看 ...
- 20155232《网络对抗》Exp2 后门原理与实践
20155232<网络对抗>Exp2 后门原理与实践 问题回答 1.例举你能想到的一个后门进入到你系统中的可能方式? 通过网页上弹出来的软件自动安装 2.例举你知道的后门如何启动起来(wi ...
- 20155302《网络对抗》Exp8 Web基础
20155302<网络对抗>Exp8 Web基础 实验内容 (1).Web前端HTML(0.5分) 能正常安装.启停Apache.理解HTML,理解表单,理解GET与POST方法,编写一个 ...
- 20155330 《网络攻防》 Exp4 恶意代码分析
20155330 <网络攻防> Exp4 恶意代码分析 实验后回答问题 (1)如果在工作中怀疑一台主机上有恶意代码,但只是猜想,所有想监控下系统一天天的到底在干些什么.请设计下你想监控的操 ...
- mfc 线程的诞生和死亡
知识点: 线程概念 线程的诞生 线程的死亡 一. 线程: 线程,是程序执行流的最小单元. 另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点 ...
- 2_C语言中的数据类型 (十)数组
1 字符串与字符数组 1.1 字符数组定义 char array[100]; 1.2 字符数组初始化 char array[100] = {'a', 'b', ...
- 异常 java.lang.IllegalArgumentException: Result Maps collection already contains value
这是因为用了一次以上(多次)mbg导致sql映射文件堆积导致的异常,删除对应的sql映射文件,然后重新生成即可. Caused by: java.lang.IllegalArgumentExcepti ...
- linux下如何解除被占用的端口号
在本例中,假设8080端口被占用. 1.查看8080端口是否被占用: netstat -anp | grep 8080输出结果:tcp 0 0 :::8080 ...
- Java和C#基本类库的区别
java.lang java .net Boolean System.Boolean Byte System. Byte Character System.Char Class System.Type ...
- 设计模式 笔记 单例模式 Singleton
//---------------------------15/04/09---------------------------- //Singleton 单例模式-----对象创建型模式 /* 1: ...