JZOJ【3072】【NOIP2012模拟10.31】掷骰子
2016-09-05 19:54
295 查看
Description
太郎和一只免子正在玩一个掷骰子游戏。有一个有N个格子的长条棋盘,太郎和兔子轮流掷一个有M面的骰子,骰子M面分别是1到M的数字.且掷到任意一面的概率是相同的.掷到几.就往前走几步.当谁走到第N格时,谁就获胜了。游戏中还有一个规则“反弹”.就是当一位选手要走到第N格外时.他就会后退(就像飞行棋进营一样)。
假设现在一位追手在A格.当他掷出B时:
1.A+B<N,走到第A+B.络,
2.A+B=N,走到第N格,获胜。
3.A+B≥N,走到第(N−(A+B−N)格
现在太郎和兔子分别在第x和y格.接下来是太郎掷骰子,太郎想知道他赢得比赛的概率就多少。
Input
一行四个整数N,M,x,y。
Output
一行一个小数.表示太郎获胜的概率。(保留6位小数)
Sample Input
10 6 1 1
Sample Output
0.541725
Data Constraint
Hint
30%的欺据,l0≤n≤100。
100%的数据.10≤n≤ 2000,1≤m,x,y≤n-1
后来大神alan_cty看着标口胡了几下,才让我们弄懂。。(⊙﹏⊙)b
蒟蒻在这里就不多说了,套用套用一下某大神的博客,写得实在是太好了,我看完之后我都不敢写题解了!感动!!
在这里大概思路是这样的
我们设f[i][j]表示太郎在位置i,兔子在位置j,太郎获胜的概率。
然后我们就分四种情况考虑
我们应该分4种情况讨论。
我们先考虑在在反弹区间里面的情况,即在区间[n-m+1,n]里面,
在这个区里面到达终点的概率都是一样的。
如果太郎和兔子都在这个区间里面,那么他们是永远走不出这个区间的,
因为无论怎样退后,都不会退到n-m这个位置。
那么概率怎样算呢?
i直接到达的概率是1m
i第二次到达的概率应该是:i第一次没有到达的概率×j第一次没有到达的概率×i这一次到达的概率,即1m×(1−1m)2
i第三次到达的概率应该是:i前两次没有到达的概率×j前两次没有到达的概率×i这一次到达的概率,即1m×(1−1m)4
i第n次到达的概率就是1m×(1−1m)2n
那么,在i这个位置的最终概率就应该把每一次到达的概率加起来,1m+1m×(1−1m)2+1m×(1−1m)4+...+1m×(1−1m)2n
将1m 提出来:1m×(1+(1−1m)2+(1−1m)4+...+(1−1m)2n)
现在在中间计算一个等比数列,公比是(1−1m)2 通过等比数列求和
算出,原式=1m×1−(1−1m)2n+11−(1−1m)2
因为n趋于无限,所以(1−1m)2n+1 趋于0。
化简得出,原式=m2m−1
所以f[i][j]=m2m−1(i,j满足它们都在在反弹区间里面)
再考虑第二种情况:i在反弹区间,而j不在。
因为i所在的区间的状态都一下的,所以除了i自己本身,就要(m-1)个相同状态,
因为i有1m 的概率到达终点,所以应该加上1m 。
f[i][j]=(m−1)×∑j+ml=j+1f[i][l]+mm2
第三种情况就与第二种相反,j在反弹区间,而i不在。
与上面类似,但需要注意的是:如果i在n-m位置,它就要1m 的概率到达终点,不过需要减去j在上一次就到达n的概率
此时的f[i][j]=(m−1)×∑i+ml=i+1f[l][j]+1m2
最后一种情况,就是i,j都不在。
这个转移很简单:
f[i][j]=∑i+ml=i+1∑j+mk=j+1f[l][k]m2
但是如果这样子会超时,我们就用sum[i][j] 表示∑nl=i∑nk=jf[l][k]
通过二维后缀和的维护,时间复杂度就变为O(N^2)
特别鸣谢:题解转自ljf的博客
CODE则是我的标
太郎和一只免子正在玩一个掷骰子游戏。有一个有N个格子的长条棋盘,太郎和兔子轮流掷一个有M面的骰子,骰子M面分别是1到M的数字.且掷到任意一面的概率是相同的.掷到几.就往前走几步.当谁走到第N格时,谁就获胜了。游戏中还有一个规则“反弹”.就是当一位选手要走到第N格外时.他就会后退(就像飞行棋进营一样)。
假设现在一位追手在A格.当他掷出B时:
1.A+B<N,走到第A+B.络,
2.A+B=N,走到第N格,获胜。
3.A+B≥N,走到第(N−(A+B−N)格
现在太郎和兔子分别在第x和y格.接下来是太郎掷骰子,太郎想知道他赢得比赛的概率就多少。
Input
一行四个整数N,M,x,y。
Output
一行一个小数.表示太郎获胜的概率。(保留6位小数)
Sample Input
10 6 1 1
Sample Output
0.541725
Data Constraint
Hint
30%的欺据,l0≤n≤100。
100%的数据.10≤n≤ 2000,1≤m,x,y≤n-1
The Solution
这种概率的问题我倒是做的挺少的,刚拿到手时,我们的人都一脸懵逼。。。后来大神alan_cty看着标口胡了几下,才让我们弄懂。。(⊙﹏⊙)b
蒟蒻在这里就不多说了,套用套用一下某大神的博客,写得实在是太好了,我看完之后我都不敢写题解了!感动!!
在这里大概思路是这样的
我们设f[i][j]表示太郎在位置i,兔子在位置j,太郎获胜的概率。
然后我们就分四种情况考虑
我们应该分4种情况讨论。
我们先考虑在在反弹区间里面的情况,即在区间[n-m+1,n]里面,
在这个区里面到达终点的概率都是一样的。
如果太郎和兔子都在这个区间里面,那么他们是永远走不出这个区间的,
因为无论怎样退后,都不会退到n-m这个位置。
那么概率怎样算呢?
i直接到达的概率是1m
i第二次到达的概率应该是:i第一次没有到达的概率×j第一次没有到达的概率×i这一次到达的概率,即1m×(1−1m)2
i第三次到达的概率应该是:i前两次没有到达的概率×j前两次没有到达的概率×i这一次到达的概率,即1m×(1−1m)4
i第n次到达的概率就是1m×(1−1m)2n
那么,在i这个位置的最终概率就应该把每一次到达的概率加起来,1m+1m×(1−1m)2+1m×(1−1m)4+...+1m×(1−1m)2n
将1m 提出来:1m×(1+(1−1m)2+(1−1m)4+...+(1−1m)2n)
现在在中间计算一个等比数列,公比是(1−1m)2 通过等比数列求和
算出,原式=1m×1−(1−1m)2n+11−(1−1m)2
因为n趋于无限,所以(1−1m)2n+1 趋于0。
化简得出,原式=m2m−1
所以f[i][j]=m2m−1(i,j满足它们都在在反弹区间里面)
再考虑第二种情况:i在反弹区间,而j不在。
因为i所在的区间的状态都一下的,所以除了i自己本身,就要(m-1)个相同状态,
因为i有1m 的概率到达终点,所以应该加上1m 。
f[i][j]=(m−1)×∑j+ml=j+1f[i][l]+mm2
第三种情况就与第二种相反,j在反弹区间,而i不在。
与上面类似,但需要注意的是:如果i在n-m位置,它就要1m 的概率到达终点,不过需要减去j在上一次就到达n的概率
此时的f[i][j]=(m−1)×∑i+ml=i+1f[l][j]+1m2
最后一种情况,就是i,j都不在。
这个转移很简单:
f[i][j]=∑i+ml=i+1∑j+mk=j+1f[l][k]m2
但是如果这样子会超时,我们就用sum[i][j] 表示∑nl=i∑nk=jf[l][k]
通过二维后缀和的维护,时间复杂度就变为O(N^2)
特别鸣谢:题解转自ljf的博客
CODE则是我的标
#include <cstdio> #include <iostream> #include <cmath> #include <algorithm> #define fo(i,a,b) for (int i=a;i<=b;i++) #define fd(i,a,b) for (int i=a;i>=b;i--) #define N 2005 using namespace std; double Suffix_Sum ; double Calc(int x,int y,int xx,int yy) { return Suffix_Sum[x][y]-Suffix_Sum[x][yy]+Suffix_Sum[xx][yy]-Suffix_Sum[xx][y]; } int main() { int n,m,x,y; scanf("%d%d%d%d",&n,&m,&x,&y); double tot=m*m; double Limit=(double)m/(m*2-1); fd(i,n,1) { fd(j,n,1) { Suffix_Sum[i][j]=Suffix_Sum[i+1][j]+Suffix_Sum[i][j+1]-Suffix_Sum[i+1][j+1]; if (i==n) { Suffix_Sum[i][j]++; continue; } if (j==n) continue; int Q=0; if (i==n-m) Q=1; if (i>n-m && j>n-m) Suffix_Sum[i][j]+=Limit; else if (i>n-m && j<=n-m) Suffix_Sum[i][j]+=(double)((m-1)*Calc(i,j+1,i+1,j+m+1)+m)/tot; else if (j>n-m && i<=n-m) Suffix_Sum[i][j]+=(double)((m-1)*Calc(i+1,j,i+m+1,j+1)+Q)/tot; else Suffix_Sum[i][j]+=(double)Calc(i+1,j+1,i+m+1,j+m+1)/tot; } } printf("%.6lf",Calc(x,y,x+1,y+1)); }
相关文章推荐
- 基于PHP代码实现中奖概率算法可用于刮刮卡、大转盘等抽奖算法
- 一步步解析Python斗牛游戏的概率
- PHP大转盘中奖概率算法实例
- python概率计算器实例分析
- Python使用random和tertools模块解一些经典概率问题
- 数学书籍备忘
- LiLei和HanMeiMei的隐式马尔可夫爱情
- php实现的一段简单概率相关代码
- 如何用随机函数rand5来构造随机函数rand7
- 概率最大骰子总和 Topcoder SRM 536 DIV1 第2题
- 把n个骰子扔在地上,所有骰子朝上一面的点数之和为S。输入n,打印出S的所有可能的值出现的概率
- UVA 11427 Expect the Expected
- 工作记录:js数组实现权重概率分配。
- JAVA抽奖算法
- 两个与π有关的数学概率
- 游戏中的概率问题
- 【JZOJ4685】礼物
- 用概率论来解释彩票
- poj3744 Scout YYF I
- HDU 3559 Frost Chain