P1365 WJMZBMR打osu! / Easy(维护两种期望的简单dp)

P1365 WJMZBMR打osu! / Easy

又被我轻轻松松切掉了呢

定义 d p [ i ] dp[i] dp[i] [ i , n ] [i,n] [i,n]获得分数的期望

那么显然 d p [ n + 1 ] = 0 dp[n+1]=0 dp[n+1]=0

但是发现无法转移,因为分数的计算需要知道 i i i后面连续 o o o的个数

而且 o o o不固定,那么我们可以维护连续 o o o的期望,记作 n u m [ i ] num[i] num[i]

这样当 a [ i ] = = ′ x ′ a[i]=='x' a[i]==x

n u m [ i ] = 0 , d p [ i ] = d p [ i + 1 ] num[i]=0,dp[i]=dp[i+1] num[i]=0,dp[i]=dp[i+1]

这个显然,自己是叉就不连续了

a [ i ] = = ′ o ′ a[i]=='o' a[i]==o

这个时候需要先减去以 i + 1 i+1 i+1开头的连续 o o o期望得分,再加上以 i i i开头连续 o o o的期望

d p [ i ] = d p [ i + 1 ] − n u m [ i + 1 ] ∗ n u m [ i + 1 ] + ( n u m [ i + 1 ] + 1 ) ∗ ( n u m [ i + 1 ] + 1 ) dp[i]=dp[i+1]-num[i+1]*num[i+1]+(num[i+1]+1)*(num[i+1]+1) dp[i]=dp[i+1]num[i+1]num[i+1]+(num[i+1]+1)(num[i+1]+1)

a [ i ] = = ′ ? ′ a[i]=='?' a[i]==?

就是各占一半的可能,加起来除以2即可

补充一下:这题从前往后转移也行

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=3e5+10;
int n;
long double dp[maxn],num[maxn];
char a[maxn];
signed main()
{
	cin >> n >> (a+1);
	dp[n+1]=0,num[n+1]=0;
	for(int i=n;i>=1;i--)
	{
		long double x=num[i+1];
		if( a[i]=='x' )	dp[i]=dp[i+1],num[i]=0;
		else if( a[i]=='o' )
		{
			dp[i]=dp[i+1]-x*x+(x+1)*(x+1);
			num[i]=num[i+1]+1;
		}
		else 
		{
			dp[i]=dp[i+1]/2+( dp[i+1]-x*x+(x+1)*(x+1) )/2;
			num[i]=( num[i+1]+1 )/2;
		}
	}
	printf("%.4Lf",dp[1]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值