>Link
luogu P1365
>Description
有一个长度为 n 的仅由
o
o
o,
x
x
x,
?
?
?三个字符组成的字符串
设字符串的分数为:其中长度为
a
a
a 的只包含
o
o
o 的子串的分数为
a
∗
a
a*a
a∗a,整个字符串的分数为极大的这样的子串分数的和。
其中对于
?
?
?,这个位置 50% 的概率是
o
o
o, 50% 的概率是
x
x
x
求这个字符串的分数期望
>解题思路
对于数学期望我们知道, E ( X ) = ∑ x i p i E(X)=∑x_ip_i E(X)=∑xipi
做的第一道期望dp
所以我们设
f
i
f_i
fi为 s[1~i] 的字符串的期望,
g
g
g为当前’o’子串的长度
对于当位 i i i可知:
- s [ i ] = = ′ o ′ : f i = f i − 1 + ( ( l e n + 1 ) 2 − l e n 2 ) = f i − 1 + 2 g + 1 , g + + s[i]=='o':f_i=f_{i-1}+((len+1)^2-len^2)=f_{i-1}+2g+1,g++ s[i]==′o′:fi=fi−1+((len+1)2−len2)=fi−1+2g+1,g++
- s [ i ] = = ′ x ′ : f i = f i − 1 , g = 0 s[i]=='x':f_i=f_{i-1},g=0 s[i]==′x′:fi=fi−1,g=0
- s [ i ] = = ′ ? ′ : s[i]=='?': s[i]==′?′: 这时答案为前两个的综合 f i = f i − 1 + ( 2 g + 1 + 0 ) / 2 , g = ( g + 1 + 0 ) / 2 f_i=f_{i-1}+(2g+1+0)/2,g=(g+1+0)/2 fi=fi−1+(2g+1+0)/2,g=(g+1+0)/2
除以二是因为题目描述的概率 状态转移方程不懂的自己手推一下就明白了
>代码
#include <iostream>
#include <cstdio>
#include <cstring>
#define db double
#define N 300005
using namespace std;
int n;
char s[N];
db f[N], g;
int main()
{
scanf ("%d", &n);
for (int i = 1; i <= n; i++)
{
s[i] = getchar();
while (s[i] != 'o' && s[i] != 'x' && s[i] != '?')
s[i] = getchar();
}
for (int i = 1; i <= n; i++)
{
if (s[i] == 'o') f[i] = f[i - 1] + 2 * g + 1, g++;
else if (s[i] == 'x') f[i] = f[i - 1], g = 0;
else if (s[i] == '?')
{
f[i] = f[i - 1] + g + 0.5;
g = (g + 1) * 0.5;
}
}
printf ("%.4lf", f[n]);
return 0;
}