【JZOJ 6026】【GDOI2019模拟2019.2.23】飞行棋

本文介绍了一种使用动态规划算法来计算飞行棋游戏中玩家获胜概率的方法。通过建立一个二维数组来记录玩家走特定步数到达终点的概率,文章详细解释了如何通过迭代更新这个数组来逼近精确的概率值。此算法考虑到走很多步仍未到达终点的概率极小,因此在计算中忽略,以达到题目要求的精度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

在这里插入图片描述

Solution

原题只要保留6位小数,

记录每个人走j步到达终点的概率,当j足够大时就可以满足进精度要求,

证明一下为什么这样可行:
我们走很多步依旧没有到达终点的概率很小,而走这么多步还依旧赢的概率更小,所以对答案的影响很小,

Code

#include <cstdio>
#include <algorithm>
#include <iostream>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define efo(i,q) for(int i=A[q];i;i=B[i][0])
#define min(q,w) ((q)>(w)?(w):(q))
#define max(q,w) ((q)<(w)?(w):(q))
using namespace std;
typedef double db;
const int N=152,M=600000;
int read(int &n)
{
	char ch=' ';int q=0,w=1;
	for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
	if(ch=='-')w=-1,ch=getchar();
	for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n;
db ans;
int a[N],b[N];
db f[2][N];
db f1[22][M+2];
db g[22][M+2],g1[M+2];
int main()
{
	freopen("feixingqi.in","r",stdin);
	freopen("feixingqi.out","w",stdout);
	int q,w;
	read(n),read(m);
	if(m==1)return printf("1.000000\n"),0;
	fo(i,1,n)read(a[i]);
	fo(i,1,m)read(b[i]);
	f[0][n]=1;
	fo(j,1,M)
	{
		int I=j&1,I1=!I;
		db t=f[I1][n]*6;
		f[I][n]=0;
		fod(i,n-1,n-6)
		{
			f[I][i]=t*0.16666666666666666666666666666666666666666666666666666667;
			t+=f[I1][a[i]]-f[I1][a[n]];
		}
		fod(i,n-7,1)
		{
			f[I][i]=t*0.16666666666666666666666666666666666666666666666666666667;
			t+=f[I1][a[i]]-f[I1][a[i+6]];
		}
		fo(i,1,m)f1[i][j]=f[I][b[i]];
	}
	fo(i,0,M)g[m+1][i]=1;
	fod(i,m,1)fod(j,M,0)
	{
		f1[i][j]+=f1[i][j+1];
		g[i][j]=f1[i][j]*g[i+1][j];
	}
	fo(i,0,M)g1[i]=1;
	fo(i,1,m)
	{
		ans=0;
		fo(j,0,M)
		{
			ans+=(g1[j]*g[i+1][j])*(f1[i][j]-f1[i][j+1]);
			g1[j]*=f1[i][j+1];
		}
		printf("%.6lf\n",ans);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值