【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 个盒子,每个盒子中有一把钥匙,对于每个盒子而言有且仅有一把钥匙能打开它.初始时,崔克茜 ...
随机推荐
- Python - for 循环
Python 3 - for 循环 这次将为大家介绍 Python 3 中的 for 循环语句的使用 for 循环的一般格式如下: for <variable> in <seque ...
- 评定星级的前端显示js
五颗星的星级评定: 说明:假设是利用三种图片显示星级评定,即 1.满亮的星 2.半亮的星星 3.不亮的星星: 满分是5分:(此处当然可以作为一个参数可变 函数传入参数grade表示当前分值. func ...
- 在 ASP.NET CORE 中使用 SESSION (转载)
Session 是保存用户和 Web 应用的会话状态的一种方法,ASP.NET Core 提供了一个用于管理会话状态的中间件.在本文中我将会简单介绍一下 ASP.NET Core 中的 Session ...
- Redis Replication
Replication 官网说明:http://www.redis.io/topics/replication Redis使用异步复制; 一个Master可以有多个Slaves; Slaves可以接收 ...
- hung task机制
最近在修改内核源码的时候一直出现格式化磁盘的时候,进程会出现状态D,看内核日志会看到如下信息: INFO: task filebench: blocked seconds. Oct :: localh ...
- 前后台分离式开发(swagger)
一.前后台分离开发(swagger) 1.安装maven 配置的maven环境变量 M2_HOME/MAVEN_HOME Path %M2_HOME%/bin 打开运行窗口:输入mvn -v,查看是否 ...
- ME_PROCESS_PO_CUST 实现采购订单行项目增强
用户希望创建采购订单时,输入行项目时,能根据采购订单类型,自动带出科目分类类别. 业务顾问看了一下配置,不能实现这个功能,所以用增强实现. 采购订单BADI增强:ME_PROCESS_PO_CUST. ...
- Python3入门(一)——概述与环境安装
一.概述 1.python是什么 Python 是一个高层次的结合了解释性.编译性.互动性和面向对象的脚本语言. Python 是一种解释型语言: 这意味着开发过程中没有了编译这个环节.类似于PHP和 ...
- 汇编 MOV -2
知识点: MOV指令 基址 内联汇编 把OD附加到资源管理器右键菜单 一.MOV指令 aaa=0x889977;//MOV DWORD PTR DS:[0x403018],0x8899 ...
- mfc 友元类
知识点 继承类成员的访问级别 友元类 继承访问控制: 基类 派生类(能否访问) public private protected 派生类类 派生类对象 派生类 派生类对象 派生类类 派生类对象 pri ...