[BZOJ 3191][JLOI 2013]卡牌游戏
2014-12-21 17:04
169 查看
觉得这题很有必要讲一下!
现在发现在做概率题,基本是向 dp 和 马尔可夫链 靠齐
但是这一题真是把我坑了,因为状态太多,马式链什么的直接死了
我一开始的想法就是用 f[i][j] 表示剩余 i 个人,现由 j 坐庄
恩~ dp 方程还是老好想的嘛~
wait! wait!! wait!!! 这尼马有后效性啊!有后效性啊!!
然后想了半天毫无进展,一看题解……
哎呦我 c
其实那个方程几乎对了,但!是!有后效性就要用重标号的方法去掉!
怎么算去了呢?
其实……谁是谁更本不重要!
如果我们对每个人 i 都重标号为 0 ,列一次方程,那么每次都只算第 0 个人 (变为 0~n-1 个人) 存活的概率 即 f[1][0] 即可
所有方程的区别只在边界条件不同而已,标号什么的完全不用管,也就没有后效性了!
然后我们只要保证 0 不 over 即可,其他的都可以不用管了
若这一轮的标号是 0~i , 然后第 j 个人 over 的话
新标号为 0~i-1, 但是这里的 j~i-1 其实是原来的 j+1~i
但是我们不用去管标号变了的问题,因为本质上是一样的
f[i][(j+a[k]-1)%(i+1)]+=f[i+1][j]/M
这么写就可以了,但是还有个问题:
0 是不能被删的我们注意到在 f[i+1] -> f[i] 时
f[i][0] 其实是 0 被删去后 1 变为 0 坐庄的概率
但 0 存活到了最后,这是无法取的(事实上若 0 活到了最后,1 就不可能坐庄)
那么 f[i][0] 其实是什么呢?
f[i][i]!
因为这是一个环,在剩余 i+1 个人时,删掉了第 i 个人,在坐庄时当然由第 0 人来,这时所有人都没有被重标号
说的不清楚还请见谅
现在发现在做概率题,基本是向 dp 和 马尔可夫链 靠齐
但是这一题真是把我坑了,因为状态太多,马式链什么的直接死了
我一开始的想法就是用 f[i][j] 表示剩余 i 个人,现由 j 坐庄
恩~ dp 方程还是老好想的嘛~
wait! wait!! wait!!! 这尼马有后效性啊!有后效性啊!!
然后想了半天毫无进展,一看题解……
哎呦我 c
其实那个方程几乎对了,但!是!有后效性就要用重标号的方法去掉!
怎么算去了呢?
其实……谁是谁更本不重要!
如果我们对每个人 i 都重标号为 0 ,列一次方程,那么每次都只算第 0 个人 (变为 0~n-1 个人) 存活的概率 即 f[1][0] 即可
所有方程的区别只在边界条件不同而已,标号什么的完全不用管,也就没有后效性了!
然后我们只要保证 0 不 over 即可,其他的都可以不用管了
若这一轮的标号是 0~i , 然后第 j 个人 over 的话
新标号为 0~i-1, 但是这里的 j~i-1 其实是原来的 j+1~i
但是我们不用去管标号变了的问题,因为本质上是一样的
f[i][(j+a[k]-1)%(i+1)]+=f[i+1][j]/M
这么写就可以了,但是还有个问题:
0 是不能被删的我们注意到在 f[i+1] -> f[i] 时
f[i][0] 其实是 0 被删去后 1 变为 0 坐庄的概率
但 0 存活到了最后,这是无法取的(事实上若 0 活到了最后,1 就不可能坐庄)
那么 f[i][0] 其实是什么呢?
f[i][i]!
因为这是一个环,在剩余 i+1 个人时,删掉了第 i 个人,在坐庄时当然由第 0 人来,这时所有人都没有被重标号
#include <cstdio> #include <cstring> const int sizeOfPlayer=55; const int sizeOfCard=55; inline int getint(); int N, M; int a[sizeOfCard]; double f[sizeOfPlayer][sizeOfCard]; int main() { N=getint(), M=getint(); for (int i=0;i<M;i++) a[i]=getint(); for (int p=0;p<N;p++) { memset(f, 0, sizeof(f)); f [(N-p)%N]=1.0; for (int i=N-1;i;i--) { for (int j=0;j<=i;j++) for (int k=0;k<M;k++) f[i][(j+a[k]-1)%(i+1)]+=f[i+1][j]/M; f[i][0]=f[i][i]; } if (p) putchar(' '); printf("%.2lf%%", f[1][0]*100); } putchar('\n'); return 0; } inline int getint() { register int num=0; register char ch; do ch=getchar(); while (ch<'0' || ch>'9'); do num=num*10+ch-'0', ch=getchar(); while (ch>='0' && ch<='9'); return num; }
说的不清楚还请见谅
相关文章推荐
- bzoj3191: [JLOI2013]卡牌游戏
- BZOJ3191 [JLOI2013]卡牌游戏
- 【BZOJ3191】【JLOI2013】卡牌游戏 [DP]
- BZOJ3191 [JLOI2013]卡牌游戏
- [bzoj3191] [JLOI2013]卡牌游戏
- [bzoj3191][JLOI2013][卡牌游戏] (概率dp)
- bzoj 3191: [JLOI2013]卡牌游戏
- 【BZOJ3191】[JLOI2013]卡牌游戏 概率DP
- bzoj3191 [JLOI2013]卡牌游戏
- bzoj千题计划202:bzoj3191: [JLOI2013]卡牌游戏
- [BZOJ3191][洛谷P2059][JLOI2013]卡牌游戏 概率DP
- BZOJ-3191 卡牌游戏JLOI2013 概率DP
- bzoj3191: [JLOI2013]卡牌游戏
- BZOJ_3191_[JLOI2013]卡牌游戏_概率DP
- 【BZOJ3191】【JLOI2013】卡牌游戏 概率DP
- 【BZOJ 3191】[JLOI2013]卡牌游戏
- 3191: [JLOI2013]卡牌游戏|概率与期望
- BZOJ 3191 JLOI2013 卡牌游戏
- 【JLOI2013合集】BZOJ3090 赛车 BZOJ3091 卡牌游戏 BZOJ3092 删除物品 BZOJ3093 地形生成
- bzoj 3191: [JLOI2013]卡牌游戏