osu合集(期望dp)

T1

EASY

我们设\(f_i\)表示到\(i\)的连续个数平方的期望。 \(g_i\)表示到到\(i\)的连续个数的期望

在维护\(f_i\)的同时维护一下\(g_i\)就行了。

转移方程: \(g_i\)= \(p_i \times g_{i-1}\);

\(f_i = p_i \times (f_{i-1} + 2 \times g_{i-1} + 1) + (1-p_i) \times f_{i-1}\)

解释一下第二个方程,

长度有\(p_i\)的概率有\(x\)变为\(x+1\)

那么分数就会增加\((x+1)^2 - x^2\)\(2 \times x - 1\)

再加上有\(1-p[i]\)的概率保持原来的不变,所以就有了上面的方程

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
char ch;
int n;
double p,g[300010],f[300010];
int main()
{
	scanf("%d",&n);
	for(int i = 1; i <= n; i++)
	{
		cin>>ch;
		if(ch == 'o') p = 1.0;
		if(ch == 'x') p = 0.0;
		if(ch == '?') p = 0.5;
		g[i] = p * (g[i-1] + 1);//维护一下区间期望长度
		f[i] = f[i-1] * (1-p) + (f[i-1] + 2 * g[i-1] + 1) * p;//维护期望得分
	}
	printf("%.4f\n",f[n]);
	return 0;
}

T2

Let's Play Osu!

和上面那个题差不多。

转移时维护一个连续个数的期望和连续个数平方的期望就水过去了。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n;
double p,f[100010],g[100010];
int main()
{
	scanf("%d",&n);
	for(int i = 1; i <= n; i++)
	{
		scanf("%lf",&p);
		g[i] = p * (g[i-1] + 1);
		f[i] = f[i-1] * (1-p) + (f[i-1] + 2 * g[i-1] + 1) * p;
	}
	printf("%.15lf",f[n]);
	return 0;
}

T3

OSU!

这个题很上面的两个题还是有点区别的,但是多想一想也就明白了

当连续的X个个数由\(x\)变为\(x+1\)

期望得分就会由\(x^3\)变为\((x+1)^3\)

也就是\(3 \times x^2 \times \ 3 \times x + 1\)

转移的时候维护三个数组,分别表示连续个数的期望,连续个数平方的期望,和期望得分。

剩下的随便水水就过了。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n;
double p[100010],f[100010],g[100010],h[100010];
int main()
{
	scanf("%d",&n);
	for(int i = 1; i <= n; i++) scanf("%lf",&p[i]);
	for(int i = 1; i <= n; i++)
	{
		h[i] = p[i] * (h[i-1] + 1);//连续个数的期望 
		g[i] = p[i] * (g[i-1] + 2 * h[i-1] + 1);//连续个数平方的期望
		f[i] = f[i-1] * (1-p[i]) + p[i] * (f[i-1] + 3 * g[i-1] + 3 * h[i-1] + 1);//期望得分
	}
	printf("%.1lf",f[n]);
	return 0;
}

期望题就是想出来与想不出来的区别。

想出来了代码也就可以实现出来了。

但是想不出来他就是 爆玲QAQ.

posted @ 2020-08-15 18:25  genshy  阅读(189)  评论(0编辑  收藏  举报