Live2D

【GDKOI 2021提高组DAY2T1】游戏 题解

【GDKOI 2021提高组DAY2】游戏(game)

Descriptions

在这里插入图片描述

Input

在这里插入图片描述

Output

在这里插入图片描述

Sample Input

2
1 2
1 2

Sample Output

6

Data Constraint

在这里插入图片描述

分析

题目大意就是一开始你有0颗星,需要进行对局,每赢一局可以获得一颗星,每输一局会扣除一颗星,给出当你持有\(i\)颗星时的胜率,问获得\(n\)颗星期望对局多少次。
比赛的时候我推了1h的式子,其实已经推出来了,后来像个NT一样在后面加了一点无关的东西结果挂了
这道题目很显然是期望DP,我们设\(f[i]\)表示从\(i-1\)颗星打到\(i\)期望对局的次数,那么转移就很显然了(\(p[i]\)指胜率,即\(x[i]/y[i]\)):
\(f[i]=(1-p[i])*(f[i]+f[i-1])+1\),后面的1表示先进行了一次对局,而有\(1-p[i]\)的几率对局失败,而对局失败后需要从i-2颗星再打到i颗星,即\((1-p[i])*(f[i]+f[i-1])\)
但是我们发现\(f[i]\)是当前需要求的,所以我们考虑转化式子:
\(f[i]=(1-p[i])*(f[i]+f[i-1])+1\)
去括号得:\(f[i]=f[i]+f[i-1]-p[i]*f[i]-p[i]*f[i-1]+1\)
\(f[i]-p[i]*f[i]\)移至等号左边得:\(p[i]*f[i]=f[i-1]+p[i]*f[i-1]+1\)
乘法分配律得:\(p[i]*f[i]=(1-p[i])*f[i-1]+1\)
两边同处\(p[i]\)得:\(f[i]=((1-p[i])*f[i-1]+1)/p[i]\)
又因为答案是在模意义下的,所以除操作时换成乘逆元就行了
记得初始化:\(f[1]=1/p[1]\)(我的\(p\)从1开始编号)
然后我们就可以愉快地\(O(n)\)转移了
最后答案即是:\(\sum f[i]\)

CODE

#include<cstdio>
#define N 1000005
#define R register int
#define mo 998244353
#define ll long long
using namespace std;
ll f[N],g[N],p[N],ans;
int n;
inline ll ksm(ll x,ll y)
{
	ll res=1;
	while (y)
	{
		if (y&1) res=(res*x)%mo;
		x=(x*x)%mo;y>>=1;
	}
	return res;
}
int main()
{
	freopen("game.in","r",stdin);
	freopen("game.out","w",stdout);
	scanf("%d",&n);
	for (R i=1;i<=n;++i)
	{
		ll x,y;scanf("%lld%lld",&x,&y); 
		p[i]=x*ksm(y,mo-2)%mo;
	}
	ans=f[1]=(1*ksm(p[1],mo-2))%mo;
	for (R i=2;i<=n;++i)
	{
		f[i]=(f[i-1]*((1-p[i]+mo)%mo)%mo+1)%mo*ksm(p[i],mo-2)%mo;
		ans=(ans+f[i])%mo;
	}
	printf("%lld\n",ans);
	return 0;
}
posted @ 2021-01-30 18:48  冷笑叹秋萧  阅读(190)  评论(0编辑  收藏  举报