[YNOI2019]游戏【概率dp+高斯消元】

博客详细介绍了YNOI2019比赛中P5415题目的解题思路,主要涉及概率动态规划(dp)和高斯消元法的应用。题目描述了一个多人游戏过程,通过分析游戏规则得出概率dp方程,并利用高斯消元求解,最后给出复杂度为O(n^3 * m^3)的解决方案。

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

P5415


SOL

对于我这样的“wen” “mang”,这题意可能有点太简略了。。
参照了 @ i_m_a_大佬的题解才理解题意。。

简述一下题意:
每次选出序列的前4个,从中等概率产生一个赢家,留在原地,剩下三个按照原来的相对位置挪到序列末尾。依次循环,知道有一个人连续赢了m场,游戏结束。问初始序列中第k位置的人(我们称作目标点)连续赢m次的概率。

用高斯消元求出概率dp方程式
不难发现,我们只需要关注当前的赢家(在第一个位置)连续赢了多少次,以及目标点的位置。
f [ i ] [ j ] 表 示 目 标 点 在 i , 1 号 点 连 续 赢 了 j 次 的 概 率 f[i][j]表示目标点在i,1号点连续赢了j次的概率 f[i][j]i1j

对于 j = = m j==m j==m,即边界,只有 f [ 1 ] [ m ] = 1 , 其 余 为 0 f[1][m]=1,其余为0 f[1][m]=10

对于 0 ≤ j < m 0\le j \lt m 0j<m,有三种情况:
1.目标点在一号点,
f [ 1 ] [ j ] = f [ 1 ] [ j + 1 ] ∗ 1 4 + f [ n ] [ 1 ] ∗ 3 4 f[1][j]=f[1][j+1]*\frac{1}{4}+f[n][1]*\frac{3}{4} f[1][j]=f[1][j+1]41+f[n][1]43

2.目标点在 2 − 4 2-4 24
f [ 2 ] [ j ] = f [ 1 ] [ 1 ] ∗ 1 4 + f [ n − 2 ] [ j + 1 ] ∗ 1 4 + f [ n − 1 ] [ 1 ] ∗ 1 2 f[2][j]=f[1][1]*\frac{1}{4}+f[n-2][j+1]*\frac{1}{4}+f[n-1][1]*\frac{1}{2} f[2][j]=f[1][1]41+f[n2][j+1]41+f[n1][1]21
( 3 , 4 3,4 3,4类似)

3.目标点在 5 − n 5-n 5n
f [ i ] [ j ] = f [ i − 3 ] [ j + 1 ] ∗ 1 4 + f [ i − 3 ] [ 1 ] ∗ 3 4 f[i][j]=f[i-3][j+1]*\frac{1}{4}+f[i-3][1]*\frac{3}{4} f[i][j]=f[i3][j+1]41+f[i3][1]43

显然这是有环的,由于方程总数为 n ∗ ( m + 1 ) n*(m+1) n(m+1),直接上高斯消元即可。
复杂度: O ( n 3 m 3 ) O(n^3m^3) O(n3m3)


CODE

#include<bits/stdc++.h>
using namespace std;
#define sf scanf
#define ri register int
#define in red()
#define gc getchar()
#define cs const
#define ll long long
#define db double
inline int red(){
	int num=0,f=1;char c=gc;
	for(;!isdigit(c);c=gc)if(c=='-')f=-1;
	for(;isdigit(c);c=gc)num=(num<<1)+(num<<3)+(c^48);
	return num*f;
}
int up,n,m,K,top=0;
inline int id(int x,int y){return (x-1)*(m+1)+y;}
db a[200][200];
inline void gauss(int n){
	for(ri i=0;i<n;++i){
		int p=i;
		for(ri j=i+1;j<=n;++j){
			if(fabs(a[j][i])>fabs(a[p][i]))p=j;
		}
		swap(a[i],a[p]);
		if(a[i][i]==0)continue;
		for(ri j=0;j<n;++j){
			if(j==i)continue;
			if(a[j][i]==0)continue;
			db k1=a[j][i]/a[i][i];
			for(ri k=n;k>=0;--k)a[j][k]-=a[i][k]*k1;
		}
	}
	for(ri i=0;i<n;++i)a[i][i]=a[i][n]/a[i][i];
}
signed main(){
//	freopen("data.in","r",stdin);
	in;
	n=in;m=in;K=in;
	up=(m+1)*n;
	//end
	a[top][id(1,m)]+=1;
	a[top][up]+=1;
	++top;
	for(ri i=2;i<=n;++i)a[top++][id(i,m)]+=1;
	//1
	for(ri i=0;i<m;++i){
		a[top][id(1,i)]+=1;
		a[top][id(1,i+1)]+=-0.25;
		a[top][id(n-2,1)]+=-0.75;
		++top;
		
		a[top][id(2,i)]+=1;
		a[top][id(n-1,1)]+=-0.5;
		a[top][id(1,1)]+=-0.25;
		a[top][id(n-2,i+1)]+=-0.25;
		++top;
		
		a[top][id(3,i)]+=1;
		a[top][id(n-1,i+1)]+=-0.25;
		a[top][id(n-1,1)]+=-0.25;
		a[top][id(n,1)]+=-0.25;
		a[top][id(1,1)]+=-0.25;
		++top;
		
		a[top][id(4,i)]+=1;
		a[top][id(n,i+1)]+=-0.25;
		a[top][id(n,1)]+=-0.5;
		a[top][id(1,1)]+=-0.25;
		++top;
	}
	for(ri i=5;i<=n;++i){
		for(ri j=0;j<m;++j){
			a[top][id(i,j)]+=1;
			a[top][id(i-3,j+1)]+=-0.25;
			a[top][id(i-3,1)]+=-0.75;
			++top;
		}
	}
	gauss(up);
	printf("%.6lf",a[id(K,0)][id(K,0)]);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值