jzoj3072 掷骰子

太郎和一只免子正在玩一个掷骰子游戏。有一个有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格.接下来是太郎掷骰子,太郎想知道他赢得比赛的概率就多少。

比赛的时候就切了,爽
第一眼看没啥头绪,看到算的是概率。
第二眼看好像概率很好算,就是前面m个数的和。
第三眼看发现反弹好像有后效性,然后发现可以滚动
第四眼看发现不会算答案…..
第五眼看还是不会算答案…..
……
第N眼(n>=100)看发现好像答案就是每一步到n的概率
第N+1眼看发现还要考虑b在之前到的情况
第N+2眼看发现直接乘上1-b先到的概率就是答案了

于是开始码码码,码的时候发现反弹可以直接镜像
有一个步数的问题,因为这个游戏是无限的,所以只要步数到了精度0.000001可以忽略不计的情况就可以直接退掉了, 大概就是15000

虽然题目看起来比较难,但是其实还是不复杂的。。。。

#include <cstdio>
#include <iostream>
#include <cstring>
typedef double ld;
using namespace std;
int n,m,x,y;
ld fx[2][4020],fy[2][4020],preX,preY,mm,ans,breach;
int main() {
    cin>>n>>m>>x>>y;
    fx[1][x]=fy[1][y]=1;
    int o=0;
    for (int i=1; i<=15000; i++) {
        memset(fx[o],0,sizeof fx[o]);
        preX=0;
        preY=0;
        for (int j=1; j<=n-1+m; j++) {
            if (j-m-1>0 && j-m-1<n) {
                preX-=fx[1-o][j-m-1];
            }
            fx[o][j]=preX/m;
            if (j>0 && j<n) { 
                preX+=fx[1-o][j];
            }
            if (j-m-1>0 && j-m-1<n) {
                preY-=fy[1-o][j-m-1];
            }
            fy[o][j]=preY/m;
            if (j>0 && j<n) {
                preY+=fy[1-o][j];
            }
        }
        for (int j=n+1; j<=n-1+m; j++) {
            fx[o][n-(j-n)]+=fx[o][j];
            fy[o][n-(j-n)]+=fy[o][j];
        }
        ans+=(1-breach)*fx[o][n];
        breach+=fy[o][n];
        o=1-o;
    }
    printf("%.6lf",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值