您的位置:首页 > 其它

概率dp && 高斯消元 专题训练

2016-02-21 23:10 295 查看
寒假真是极度荒废的,想补一补自己的概率方面的知识,感觉也没很好的补,只是把概率dp和高斯消元的一些东西搞懂了,难的也不会做。

什么期望的线性递推啊,概率公式,高深的基本都没学

lightoj 1027

这是以前碰到的老概率题了,当年压根不会,现在会了

有n个门让你选,每个门有一个数字,正数代表x分钟后出去,负数代表x分钟后回到起点重新开始

然后问你出去的时间期望是多少分钟

这题就是把正负时间统计一下,你每次选择出去的概率是pos/n,回去的概率是neg/n,然后你出去的平均时间是正数加起来的平均值,回去的时间是负数加起来的平均值,然后类似正常的求期望就好了,公式推导化简一下,得到最后的答案就行了

AC代码:http://paste.ubuntu.net/15157341/

lightoj 1030

这题应该是飞行棋,然后每个位置上有一个数字,6面骰子,问你从1走到n,走过的数的和的期望

概率dp求期望,一般要倒着dp,为什么呢,dp[i]表示从i走到n的期望,因为你从i走到i+1,i+2,。。。i+6,i有1/6的概率转移到比如i+1,然后得到dp[i+1],所以dp[i]+=1/6(dp[i+1]+dp[i+2]+...+dp[i+6])。如果不满6格不一定是1/6

AC代码:http://paste.ubuntu.net/15157399/

lightoj 1038

给你一个数n,然后从他的因子中选择一个d,然后得到n/d,然后还是这样操作,问你得到1需要的次数的期望

dp[i]=1+(sigma(dp[i/j]))/g[i]; j是i的因子,g[i]是i的因子的个数

然后j可能等于1,所以需要化简这个公式,把dp[i]移到一侧,然后得到结果,用递归写就能解决

AC代码:http://paste.ubuntu.net/15157453/

lightoj 1079

这题是你去抢银行,然后被抓的概率小于p的话就是安全,然后告诉你每个银行的钱和被抓的概率,求不被抓的情况下拿到最多的钱

这个很明显就是个背包啊,但是状态很容易想错

首先是被抓的概率不能相乘,不然你被抓的概率是越来越小,也不能想加,应该是不被抓的概率相乘,其次我傻逼的把概率当作下标来做,然后一直跪,毕竟没告诉我精度是多少

其实应该dp[i]表示抢到i个钱的时候不被抓的最大概率,然后dp[i]=max(dp[i-j]*(1-p));

AC代码:http://paste.ubuntu.net/15157500/

lightoj 1104

一年有n天,然后问你至少找多少个人,让其中有两个人在同一天生日的概率大于等于0.5;

其实要求所有人都不再同一天生日的概率小于等于0.5

其实就是A(n,x)/n^x <=0.5就行了

AC代码:http://paste.ubuntu.net/15157601/

lightoj 1151

这题是有100个位置,然后骰子可以掷出1-6,走1-6步,但是还有蛇和楼梯,所以这其实是一个有环的期望问题

e[i]=1+e[i+1]+e[i+2]+...+e[i+6];

如果i处有楼梯或者蛇,e[i]=e[go[i]];

构造好矩阵,直接套高斯消元的期望模版就行了

AC代码:http://paste.ubuntu.net/15157659/

lightoj 1248

这题是给你个n面的骰子,然后问你n面全部扔出来的次数的期望

dp[i]表示已经扔出来了i面的期望,他可以转移到dp[i]和dp[i+1]

dp[i]=i/n*dp[i]+(n-i)/n*dp[i+1]+1;

dp[i]=dp[i+1]+n/(n-i);

AC代码:http://paste.ubuntu.net/15157824/

lightoj 1265

给你一些老虎和鹿,然后还有你,两两碰到会发生一些事情,问你存活下来的概率

先找出你能存活的情况,然后dp一下

AC代码:http://paste.ubuntu.net/15157958/

lightoj 1274

给你一个长度s的字符串,然后告诉你yes和no加起来有n个,然后可以换出来yes的个数和no的个数,然后yes可以看成1,no看成0,然后问你对于所有排列,把这个排列右移一位然后左边添上yes之后和原来的串不一样的个数的期望的平均

讲道理这题我没怎么懂题意,其实就是求排列里面相邻不同的个数把,然后问你有a个1,b个0的时候,能出现的相邻不同的个数的期望,如果第一位是0的话,还要加1

dp[i][j][flag]表示前面i个有j个1,并且第i位是flag,然后就这么瞎搞吧,然后你取到1或者0的概率算一下,然后搞一下

最后输出dp[0][0][1],因为最前面要放个1,所以如果第一位是0的话还要+1,然后数组开不下,所以要用滚动数组

感觉这题表达的也不清楚,反正记住期望要倒着算,以后碰到题目还是要随机应变啊

AC代码:http://paste.ubuntu.net/15158239/

lightoj 1284

这题是给你个三维空间,起初都是off,然后你选两个点,两点之间的按钮都被打开(如果开着就关闭),然后问你k次操作后是on的个数的期望

这题其实要考虑每个位置被打开的概率(操作奇数次)

然后就是算这个一次操作里位置被选中的概率p,那么就是(1-x坐标没被选中的概率)*(1-y坐标没被选中的概率)*(1-z坐标没被选中的概率)

然后要算k次里被选中奇数次,记p
为n次里选中奇数次的概率,g
为n次里选中偶数次的概率

p
=1-g
;

g
=p[n-1]*p+(1-p)*g[n-1]=p[n-1]*p+(1-p)*(1-p[n-1])=1+2*p*p[n-1]-p[n-1]-p;

p
=(1-2p)*p[n-1]+p;

p
-1/2=(1-2p)*(p[n-1]-1/2);

p[0]=0;

求出p
,然后对每个位置ans+=p


AC代码:http://paste.ubuntu.net/15158463/

poj 2151

给你几个队伍,然后每个队伍做对每题的概率,让你求每个队至少做出1题,并且至少一个队伍做出来n题的概率

先求出每个队伍都做不出题的概率,然后减一下,乘一下,得到至少1题的概率,dp求出每个队过不满n题的概率,然后乘起来每个队都过题但是不满n题的概率,然后上面个概率减去下面个就好了。

概率一定要想清楚,我开头没想清楚,就乘了然后wa

AC代码:http://paste.ubuntu.net/15243169/

codeforces 148D

这题是说有黑的b个白的w个,然后两个人开始抓老鼠,谁抓到白的就赢,然后龙每次抓,剩下的都会随即逃走一只,然后如果没有老鼠了,算龙赢,问你公主赢的概率

这题要找出公主的状态转移,而不能一会考虑公主一会考虑龙

dp[i][j]是剩下i个白,j个黑的时候公主赢的概率,于是可以转移到dp[i][j]=i/(i+j)+.....

后面是公主抓黑的,龙不能抓白的,所以也是黑的,然后随即跑一个是黑的或者白的,就这两个转移

AC代码:http://paste.ubuntu.net/15243211/

poj 3071

踢足球,然后给你每个队战胜其他队的概率,然后貌似是相邻的两两先进行比赛,然后问你谁最终胜出的概率最高

2的n次个球队,所以n轮就能有人最终胜出,所以只要算每轮,他赢得概率是多少,他需要战胜上一轮对面的每个对手

dp[j][i]+=dp[j][i-1]*dp[k][i-1]*p[j][k];

AC代码:http://paste.ubuntu.net/15243241/


hdu 4405
飞行棋,倒着概率dp求期望
AC代码:http://paste.ubuntu.net/15243498/

poj 3744
好像是说你一次走1一步的概率是p,两步的概率是1-p,然后给你几个地雷的位置,问你从1开始走到安全的概率
先给地雷排序,如果有两个连在一起的就是0,然后如果没有连在一起的,那么就从最后一个雷的后面一格开始算,假设从这个往1开始走,然后这个地方安全的概率是1,然后走过这个雷,概率是1-p,再前面一格是p(1-p),然后因为数据很大,不能直接推dp[i]=pdp[i+1]+(1-p)dp[i+2];所以就用矩阵快速幂搞一下就好了,注意点细节就好了
AC代码:http://paste.ubuntu.net/15333587/

zoj 3329

题意:有三个骰子,分别有k1,k2,k3个面。
每次掷骰子,如果三个面分别为a,b,c则分数置0,否则加上三个骰子的分数之和。
当分数大于n时结束。求游戏的期望步数。初始分数为0

设dp[i]表示达到i分时到达目标状态的期望,pk为投掷k分的概率,p0为回到0的概率
则dp[i]=∑(pk*dp[i+k])+dp[0]*p0+1;
都和dp[0]有关系,而且dp[0]就是我们所求,为常数
设dp[i]=A[i]*dp[0]+B[i];
代入上述方程右边得到:
dp[i]=∑(pk*A[i+k]*dp[0]+pk*B[i+k])+dp[0]*p0+1
=(∑(pk*A[i+k])+p0)dp[0]+∑(pk*B[i+k])+1;
明显A[i]=(∑(pk*A[i+k])+p0)
B[i]=∑(pk*B[i+k])+1
先递推求得A[0]和B[0].
那么  dp[0]=B[0]/(1-A[0]);


复制kuangbin大神的题解,这种有环的期望问题一般用高斯消元,但是这题只有和dp[0]有环,并且求的就是dp[0],所以只要迭代就行,先列出dp[i]的式子,然后假设dp[i]为dp[0]的函数,然后带入dp[i+k],找到系数之间的关系就行了,这种题目第一次做完之后还是没有立马掌握
AC代码:http://paste.ubuntu.net/15333652/

hdu 4035

dp求期望的题。
题意:
有n个房间,由n-1条隧道连通起来,实际上就形成了一棵树,
从结点1出发,开始走,在每个结点i都有3种可能:
1.被杀死,回到结点1处(概率为ki)
2.找到出口,走出迷宫 (概率为ei)
3.和该点相连有m条边,随机走一条
求:走出迷宫所要走的边数的期望值。

设 E[i]表示在结点i处,要走出迷宫所要走的边数的期望。E[1]即为所求。

叶子结点:
E[i] = ki*E[1] + ei*0 + (1-ki-ei)*(E[father[i]] + 1);
= ki*E[1] + (1-ki-ei)*E[father[i]] + (1-ki-ei);

非叶子结点:(m为与结点相连的边数)
E[i] = ki*E[1] + ei*0 + (1-ki-ei)/m*( E[father[i]]+1 + ∑( E[child[i]]+1 ) );
= ki*E[1] + (1-ki-ei)/m*E[father[i]] + (1-ki-ei)/m*∑(E[child[i]]) + (1-ki-ei);

设对每个结点:E[i] = Ai*E[1] + Bi*E[father[i]] + Ci;

对于非叶子结点i,设j为i的孩子结点,则
∑(E[child[i]]) = ∑E[j]
= ∑(Aj*E[1] + Bj*E[father[j]] + Cj)
= ∑(Aj*E[1] + Bj*E[i] + Cj)
带入上面的式子得
(1 - (1-ki-ei)/m*∑Bj)*E[i] = (ki+(1-ki-ei)/m*∑Aj)*E[1] + (1-ki-ei)/m*E[father[i]] + (1-ki-ei) + (1-ki-ei)/m*∑Cj;
由此可得
Ai =        (ki+(1-ki-ei)/m*∑Aj)   / (1 - (1-ki-ei)/m*∑Bj);
Bi =        (1-ki-ei)/m            / (1 - (1-ki-ei)/m*∑Bj);
Ci = ( (1-ki-ei)+(1-ki-ei)/m*∑Cj ) / (1 - (1-ki-ei)/m*∑Bj);

对于叶子结点
Ai = ki;
Bi = 1 - ki - ei;
Ci = 1 - ki - ei;

从叶子结点开始,直到算出 A1,B1,C1;

E[1] = A1*E[1] + B1*0 + C1;
所以
E[1] = C1 / (1 - A1);
若 A1趋近于1则无解...


这题就是叶子节点和分支节点要分开讨论,然后从叶子开始往根走,按照上面的递推一步步搞,刚推了一遍,推对了,不过还是很烦啊orz
AC代码:http://paste.ubuntu.net/15333722/

概率dp好难,有的是难以找到转移,有的是像这种迭代的难化简。仍需努力和多练啊,留几个难题以后做

/************************************************************************高斯消元*****************************************************************************************************/

高斯消元有大概三种类型:开关问题,同余方程,数学期望
开关问题就是最常见的,翻转啊,开灯关灯啊,就0,1两种状态,然后一般会有好几种题型
我的模板矩阵都是从0存到n-1的,然后传递过去参数是n和m
开关问题模板:http://paste.ubuntu.net/15333755/
同余方程模板:http://paste.ubuntu.net/15333757/
数学期望模板:http://paste.ubuntu.net/15333758/

poj 1830
求有解的情况下有多少种方法
先套高斯消元的模板,然后得到有几个按钮是必须为1,还有一些自由变元,自由变元的个数x,(1<<x)就是解的个数了
AC代码:http://paste.ubuntu.net/15333761/

poj 3185
这题求解灯全部关掉的情况下, 需要操作的最少的开关
也是套模板,然后check自由变元,把某些自由变元置为1的时候,需要翻的个数,找到最小即可
AC代码:http://paste.ubuntu.net/15333774/

poj 2065
这题是给你个公式f(k),然后给你n个变量a0....an-1
然后公式是每个变量的参数是k^i,,k是这会是第几个字符,然后f(k)=s[k]-‘a'+1,如果s[k]==’*',f(k)=0;
然后运算结果都要mod p,所以套一下同余方程的模板就好了,同余方程后面还要用到求解逆元(因为要除),所以套用了exgcd
AC代码:http://paste.ubuntu.net/15333796/

hdu 3949
这题给你n个数,然后问你这些数随便异或,可以得到一些数,问你得到的数里面第k小的是多少
这题和CCPC的E题很像,至今难忘,因为当时不会做,其实这题是把每个数的每位看成矩阵然后高斯消元搞,然后有些位必为1,怎么说呢,不造这个怎么叫,然后如果有cnt个位为1,就可以得到(1<<cnt)种答案,不过如果cnt>=n的话,得到的答案要-1,因为必须取,加上每位都有1,所以不可能得到所有1都不取的结果,然后就是输入k,然后判断加构造这个答案了,如果上面cnt<n了,k也要-1,然后因为可以取到0,然后看k里面的0和1的分布,把对应位的元素异或起来
这样:
if(k>tmp) printf("-1\n");

else{

    if(cnt<n) k--;

    for(int i=0;i<cnt;i++){

        if(k&(1LL<<i)) ans^=a[cnt-i];

    }

    printf("%I64d\n",ans);

}
这题十分的orz,所以必须是做成模版了,虽然其实原理和开关问题差不多
AC代码:http://paste.ubuntu.net/15333820/

poj 1222
这题是翻一块,可以翻动周围4个,问你需要翻哪些,才能得到全0的(或者全1,记不得了)
也是开关问题啊就是构造矩阵的时候要考虑边上的
还有就是开关问题的模板一定要用上面的,从0开始然后判断i!=r,年神开头写的模板不对
不贴代码了,水题

高斯消元暂时没有学的很深,就了解了模板和一些简单的题,还有就是那个ccpc的E题,好好燃了

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: