您的位置:首页 > 其它

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

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));
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息