题意

有\(n\)场比赛,他每次等概率地选择一场,选择的比赛可能有没ac过的题,他一定会ac这次比赛中的某一道,并说我好菜啊。如果全ac过了,也会说我好菜啊。求期望说多少次我好菜啊。

注意题目中每场题的范围是1到3

我们可以把相同题数的场看成同一种,那就有三种

把题意抽象成取球游戏,就是\(i_1\)类型的球有\(a_1\)个,\(i_2\)类型的球有\(a_2\)个,\(i_3\)类型的球有\(a_3\)个,即将数量一样的比赛抽象成同一种球,问期望用多少次可以取到所有不同的球。不同种类的球取出会带来不同的变化,取了\(i_1\)类型的球会导致剩余没取的个数减一,但取了\(i_3\)类型的球因为这个比赛的题目数减一变成\(i_2\)类型,取了\(i_2\)类型的球就变成\(i_1\)类型的。

这个问题挺难的,那我们就先看一下最基本的取球游戏(彩票收集问题)

前序知识

最基本的取球问题就是\(n\)个球,求将每个球至少取一次,问期望用多少次可以取到所有不同的球。

假设现在还剩下\(i\)个球没取过,那么这时取到没取过的球的概率是

\(P=i / N\)

由于这个事件满足几何分布,所以他的期望就是\(1/p\),就是\(N/i\)

几何分布(Geometric distribution)是离散型概率分布。其中一种定义为:在n次伯努利试验中,试验k次才得到第一次成功的机率。详细地说,是:前k-1次皆失败,第k次成功的概率。

用\(dp[i]\)表示剩下\(i\)个球没取时多少次取到剩下所有不同的球的期望

那么可以得出一下递推式:

\[dp[0]=0
\]

由期望的可加性:

\[dp[i]=N/i+dp[i-1]
\]

本题题解

这题就是取球游戏改编的,但是状态比较多,变成了3维的

根据上面的递推式和本题题意,得出以下状态转移方程,令\(dp[i][j][k]\)为剩下三种球没取时多少次取到所有不同的球的期望。再令\(M=i+j+k\)

\[dp[0][0][0]=0
\]

因为当前的状态有三种可能状态转移,并且每场比赛的选择都是等概率的,将后继状态已经求出的期望加上当前状态取出不同的球的期望。

\[dp[i][j][k]=N/M+dp[i-1][j][k]* i/M+dp[i+1][j-1][k] * j/M+dp[i][j+1][k-1]* k/M
\]

化简一下就是(好像没怎么化简)

\[dp[i][j][k]=(N+dp[i-1][j][k] * i+dp[i+1][j-1][k] * j+dp[i][j+1][k-1] * k)/M
\]

代码

可以将\(k\)优化一下,枚举所有的状态,然后暴力转移

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int maxn = 505;
const int mod=17680321;
ll inv[maxn];
ll num[4];
ll dp[maxn][maxn][2];
void init(int n){
inv[1]=1;
for(int i=2;i<=n;++i){
inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
int n;
cin>>n;
init(n);
for(int i=1,a;i<=n;++i) {
cin>>a;
num[a]++;
}
dp[0][0][0]=0;
int t=1;
for (int k = 0; k <= num[3]; k++) {
t ^= 1;
for (int j = 0; j +k<= n; j++){
for (int i = 0; i +k+j<= n; i++){
if (i || j || k) {
dp[i][j][t] = 1ll * n * inv[i + j + k] % mod;
if (i)dp[i][j][t] = (dp[i][j][t] + 1ll * dp[i - 1][j][t] * i % mod * inv[i + j + k]) % mod;
if (j)dp[i][j][t] = (dp[i][j][t] + 1ll * dp[i + 1][j - 1][t] * j % mod * inv[i + j + k]) % mod;
if (k)dp[i][j][t] = (dp[i][j][t] + 1ll * dp[i][j + 1][t ^ 1] * k % mod * inv[i + j + k]) % mod;
}
}
} }
cout<<dp[num[1]][num[2]][t]<<endl;
return 0 ;
}

总结

与常规的求解不同,数学期望经常逆向推出。

常言道:"正向推概率,反向推期望"

为什么呢?

大家可以百度一下(逃

博客:https://www.cnblogs.com/smallocean/

[概率DP]相逢是温厚的更多相关文章

  1. Codeforces 28C [概率DP]

    /* 大连热身D题 题意: 有n个人,m个浴室每个浴室有ai个喷头,每个人等概率得选择一个浴室. 每个浴室的人都在喷头前边排队,而且每个浴室内保证大家都尽可能均匀得在喷头后边排队. 求所有浴室中最长队 ...

  2. HDU 4405 Aeroplane chess (概率DP)

    题意:你从0开始,要跳到 n 这个位置,如果当前位置是一个飞行点,那么可以跳过去,要不然就只能掷骰子,问你要掷的次数数学期望,到达或者超过n. 析:概率DP,dp[i] 表示从 i  这个位置到达 n ...

  3. POJ 2096 Collecting Bugs (概率DP)

    题意:给定 n 类bug,和 s 个子系统,每天可以找出一个bug,求找出 n 类型的bug,并且 s 个都至少有一个的期望是多少. 析:应该是一个很简单的概率DP,dp[i][j] 表示已经从 j ...

  4. POJ 2151 Check the difficulty of problems (概率DP)

    题意:ACM比赛中,共M道题,T个队,pij表示第i队解出第j题的概率 ,求每队至少解出一题且冠军队至少解出N道题的概率. 析:概率DP,dp[i][j][k] 表示第 i 个队伍,前 j 个题,解出 ...

  5. 概率DP light oj 1030

    t组数据 n块黄金 到这里就捡起来 出发点1 到n结束  点+位置>n 重掷一次 dp[i] 代表到这里的概率 dp[i]=(dp[i-1]+dp[i-2]... )/6  如果满6个的话 否则 ...

  6. hdu 4050 2011北京赛区网络赛K 概率dp ***

    题目:给出1-n连续的方格,从0开始,每一个格子有4个状态,左右脚交替,向右跳,而且每一步的步长必须在给定的区间之内.当跳出n个格子或者没有格子可以跳的时候就结束了,求出游戏的期望步数 0:表示不能到 ...

  7. [转]概率DP总结 by kuangbin

    概率类题目一直比较弱,准备把kuangbin大师傅总结的这篇题刷一下! 我把下面的代码换成了自己的代码! 原文地址:http://www.cnblogs.com/kuangbin/archive/20 ...

  8. SGU 422 Fast Typing(概率DP)

    题目大意 某人在打字机上打一个字符串,给出了他打每个字符出错的概率 q[i]. 打一个字符需要单位1的时间,删除一个字符也需要单位1的时间.在任意时刻,他可以花 t 的时间检查整个打出来的字符串,并且 ...

  9. HDU 4050 wolf5x(动态规划-概率DP)

    wolf5x Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Sub ...

随机推荐

  1. 美素数(HDU 4548)(打表,简化时间复杂度)

    相信大家都喜欢美的东西,让我们一起来看看美素数吧. 问题是这样的:一个十进制数,如果是素数,而且它的各位数字和也是素数,则称之为"美素数",如29,本身是素数,而且2+9 = 11 ...

  2. electron app弹出默认对话框后页面失去焦点问题

    最近再做electron app程序的做删除数据操作的时候遇到一个诡异的bug,页面点击删除按钮后,弹出确认对话框后,页面失去焦点,文本框无法点击输入任何参数,但是使用浏览器操作正常,最后确定是ele ...

  3. POJ 2186:Popular Cows Tarjan模板题

    Popular Cows Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 25945   Accepted: 10612 De ...

  4. Python笔记_第五篇_Python数据分析基础教程_NumPy基础

    1. NumPy的基础使用涵盖如下内容: 数据类型 数组类型 类型转换 创建数组 数组索引 数组切片 改变维度 2. NumPy数组对象: NumPy中的ndarray是一个多维数组对象,该兑现共有两 ...

  5. C# 串口编程,扫码枪使用

    一.串口通信简介 串行接口(串口)是一种可以将接受来自CPU的并行数据字符转换为连续的串行数据流发送出去,同时可将接受的串行数据流转换为并行的数据字符供给CPU的器件.一般完成这种功能的电路,我们称为 ...

  6. JS高级学习笔记(2)之js多线程

    参考大神:Javascript多线程 web worker ---- 6.Web Worker 概述 截图过来: 线程之间的通信 let worker = new Worker(‘js文件路径’) 主 ...

  7. SQL基础教程(第2版)第3章 聚合与排序:3-3 为聚合结果指定条件

    第3章 聚合与排序:3-3 为聚合结果指定条件 ● 使用COUNT函数等聚合函数对表中数据进行汇总操作时,为其指定条件的不是WHERE子句,而是HAVING子句.● 聚合函数可以在SELECT子句. ...

  8. dockerfile---apt-get install vim 时 Unable to locate package vim

    在学习 dockerfile 的时候,发现编写的 Dockerfile 中的 apt-get install 命令无法找到要安装的包,所以记录一下这次发生的错误. 环境:宿主机:windows 10 ...

  9. 调度算法FCFS、SJF和优先权调度的介绍和例题

    调度算法 一.先来先服务FCFS (First Come First Serve) 1.思想: 选择最先进入后备/就绪队列的作业/进程,入主存/分配CPU 2.优缺点 优点:对所有作业/进程公平,算法 ...

  10. C语言获取本机ip

    一.参考网址 1.c语言获取本机IP 二.源码 #include <stdio.h> #include <stdint.h> #include <stdlib.h> ...