进入大学之后发现自己对概率问题很不感冒,其实一直都是这样,高中就没好好读数学。概率不好的结果就是对概率类dp掌握得just so so,因为对这类dp的状态和转移不敏感,要么是yy,要么是花很长时间想状态想转移。
现在痛下决心,好好虐待自己一段时间,做下概率dp。
Codeforces 148D Bag of mice
状态转移方程比较难想,开虚拟比赛的时候花了50分钟硬是没AC.设win[i][j]表示公主赢的概率,lost[i][j]表示龙输的概率,然后根据题意进行转移。状态转移方程如下:
win[i][j] = i * 1.0 / (i + j); //i只白老鼠j只黑老鼠时公主选白老鼠
win[i][j] += lost[i][j-1] * j * 1.0 / (i + j); //i只白老鼠j只黑老鼠时公主选黑老鼠,但公主选完黑老鼠后龙还是输了
lost[i][j] = j * 1.0 / (i + j) * win[i-1][j-1] * (i * 1.0 / (i + j - 1)); //i只白老鼠j只黑老鼠时龙选黑老鼠,选完后跳出去只白老鼠
lost[i][j] += j * 1.0 / (i + j) * win[i][j-2] * ((j - 1) * 1.0 / (i + j - 1)); //i只白老鼠j只黑老鼠时龙选黑老鼠,选完后跳出去只黑老鼠
Sgu 495 Kids and Prizes
比较简单的概率DP。m个人选n个礼物,问选中的期望。因为每个人选择礼物是独立,那么猜想求解过程n只是用来求概率。设dp[i]表示第i个人选中礼物的概率,np[i]表示第i个人不选中礼物的概率。那么dp[i] = dp[i-1] * np[i-1] + dp[i-1] * (dp[i-1]-1.0/n),表示:如果上一个人没选中,那么本次选中的概率和上次选中的概率一样是dp[i-1],如果上次已经选中,那么本次选中的概率是dp[i-1]-1.0/n。而np[i] = 1- dp[i];这种方法复杂度是O(m),其实O(1)就可以了。从反方向求不被选中的期望,那么答案就是n-n*((n-1)/n)^m,每个礼物不被m个人选中的概率是((n-1)/n)^m,因为每个礼物都一样,所以直接乘n就Ok。
Zoj 3383 Patchouli's Spell Cards
概率DP,选m个位置填充,每个填充的数的范围是1..n,问至少有l个数相同的概率。从反面来考虑,求不出现l个相同数的概率p,1-p既是答案。模型转换后就可以进行DP了,设dp[i][j]表示选到第i个数填充了j个位置的方案数,那么dp[i][j] = dp[i-1][j-k] + C[m-(j-k)][k](k < l && k <=j),,然后求出所有方案书total,ans = (total - dp[n][m]) / total.这种方法复杂度是O(n*m*l),其实有种复杂度为O(min(n,m)*min(n,m)*l),dp[i][j]表示选了i个数填充j个位置的方案数,这里的i不必是1...i,只要是i个不同的数即可,这样和n就没多大关系,转移方程类似。数很大要用大数。
Zoj 3460 Help Me Escape
浙大月赛的题目,比赛的时候想到了做法,但是被一题字符串卡住,没来得及敲。题目的大概意思是一只吸血鬼每次随机的选择n个洞中的任意一个,如果该吸血鬼的攻击值大于该洞ci那么直接可以花费Ti的时间就可以出去,不然要奋斗一天该吸血鬼攻击值增加ci再 随机选择n个洞.口设dp[i]表示攻击力为i时逃跑的期望,那么状态转移方程就为dp[i] = sum(wi) / n,当ci < i时,wi = (1+sqrt(5))/ 2 * ci * ci,当ci >=i时wi = 1 + dp[i+ci]。可以逆序进行状态转移也可以用记忆化搜索,记忆化搜索更容易理解。
Hdu 4405 Aeroplane chess
从位置0开始,每步随机走1,2,3,4,5,6个位置,问走到大等于n位置的期望步数,还有一些位置带有限制,某些xi对应着yi,表示到xi就必须马上走到yi,不算一步。和上题很像,更简单些,
简单点好想点的做法是设dp[i]表示到i时的期望,p[i]表示到i时的概率,那么dp[i] += (dp[j] + p[j]) * 1 / 6.0,p[i] += p[j] * 1 / 6.0,(从j走到i) 当next[i] != i时dp[i] = dp[j],p[i] = p[j];最后的答案是dp[n];这个公式是这样推导来的,假设dp[j] = day * p,那么dp[i] = (day + 1) *p* 1 / 6.0,即dp[i] = (dp[j] + p[j]) * 1 / 6.0.
化解后,dp[i]表示到达i位置的期望天数.dp[i] = dp[j] (next[i] == i), dp[i] += (dp[j] + 1) * 1 / 6.0。
Hdu 4336 Card Collector
状态压缩DP解之,dp[i]表示i这个状态到最终状态需要的期望卡片数,dp[i] =dp[i] * myself + sum( dp[j] * p[k] = sum( dp[j] * p[k]) / (1-myself)(i|k=j且i!=j,myself表示保持原状的概率).
这道题其实是我YY用容斥原理过的,看测试数据很像可以2^n枚举,然后把把枚举到的卡片概率加起来算期望,奇数加偶数减,然后就过了。想不清楚为什么可以用容斥原理,然后就找了个挺靠谱的解释自我安慰,E1表示买买到1的期望,E1 = 1/p1,也就是说E1包里面肯定包含1这张卡片,当我们计算E1和E2时,是不是会有一种情况:我们想要卡片1的时候已经买到了卡片2,然后我们又要计算买卡片2的期望,正是因为这样的交集使得我们可以用容斥,交集的期望E12 = 1 / (p1 +p2) 表示肯定买到1、2中的其中一包,E123就表示肯定买到1、2、3中的某一种,我们在计算E12,E13,E23的时候E123多减了一次,要加回来,以此类推....
148D代码
SGU 495代码:
Zoj 3383 代码
Zoj 3460 代码
Hdu 4405 代码