Description
某一天WJMZBMR在打osu~~~但是他太弱逼了,有些地方完全靠运气:(
我们来简化一下这个游戏的规则
有 (n) 次点击要做,成功了就是o
,失败了就是x
,分数是按combo计算的,连续 (a) 个combo就有 (a imes a) 分,combo就是极大的连续o
。
比如ooxxxxooooxx
x,分数就是 (2 imes 2 + 4 imes 4 = 4 +16=20)。
Sevenkplus闲的慌就看他打了一盘,有些地方跟运气无关要么是o
要么是x
,有些地方o
或者x
各有50%的可能性,用?
号来表示。
比如oo?xx
就是一个可能的输入。 那么WJMZBMR这场osu的期望得分是多少呢?
比如oo?xx
的话,?
是o
的话就是oooxx
=> 9,是x的话就是ooxxx
=> 4
期望自然就是 (4+9)/2=6.5(4+9)/2 =6.5(4+9)/2=6.5 了
Input
第一行一个整数 n ,表示点击的个数
接下来一个字符串,每个字符都是o
,x
,?
中的一个
Output
一行一个浮点数表示答案
四舍五入到小数点后 4 位
如果害怕精度跪建议用long double或者extended
Hint
(Nleq 300000)
Solution
显然期望 (dp) 的套路。定义两个数组 (f[i],g[i]) 分别表示到 (i) 的总得分和以 (i) 为结尾的 (combo) 长度。
如果当前是o
根据 ((x+1)^2=x^2+2x+1),(f[i]=f[i-1]+2*g[i-1]+1),同时 (g[i]=g[i-1]+1)
如果当前是x
(f[i]=f[i-1],g[i]=0)
如果当前是?
因为各有 (0.5) 的可能性,所以 (f[i]=0.5*(f[i-1]+2*g[i-1]+1)+0.5*f[i-1],g[i]=0.5*(g[i-1]+1)+0.5*0)
Code
#include<cstdio>
#define N 300005
#define db double
int n;
db f[N];
db g[N];
char ch[N];
signed main(){
scanf("%d",&n);
scanf("%s",ch+1);
for(int i=1;i<=n;i++){
if(ch[i]=='o'){
f[i]=f[i-1]+2*g[i-1]+1;
g[i]=g[i-1]+1;
} else if(ch[i]=='x'){
f[i]=f[i-1];
g[i]=0;
} else{
g[i]=(g[i-1]+1)/2.0;
f[i]=0.5*f[i-1]+0.5*(f[i-1]+2*g[i-1]+1);
}
}
printf("%.4lf
",f[n]);
return 0;
}