题目描述
某一天(WJMZBMR)在打(osu)~~~但是他太弱逼了,有些地方完全靠运气(QaQ)
我们来简化一下这个游戏的规则
有(n)次点击要做,成功了就是(o),失败了就是(x),分数是按(comb)计算的,连续(a)个(comb)就有(a imes a)分,(comb)就是极大的连续(o)。比如(ooxxxxooooxxx),分数就是(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)over2}=6.5)了
输入格式
第一行一个整数(n),表示点击的个数
接下来一个字符串,每个字符都是(ox?)中的一个
输出格式
一行一个浮点数表示答案
四舍五入到小数点后(4)位
如果害怕精度跪建议用(long double)或者(extended)
样例输入
4
????
样例输出
4.1250
数据范围与提示
(n<=300000)
(osu)很好玩的哦
(WJMZBMR)技术还行(雾),(x)基本上很少呢
分析
这个题和(OSU!)其实差别不大,也就是每个位置都有两种情况,然后就可以开始分析状态转移方程了:
首先利用两个数组(f[i])和(g[i]),一个代表前(i)总得分,另一个代表前(i)总长度。
总长度这个当然很好进行状态转移,首先是当这一位是(o),那么就可以直接(g[i]=g[i-1]+1)。其次是这一位成为了(x),那么(g[i])就置为(0)。第三种就是(?)的情况,因为(o)和(x)各为(50\%)的概率,所以(g[i]=0.5 imes(g[i-1]+1)+0 imes 0.5),到最后(g[i])的状态转移方程就是(g[i] ={ {g[i-1]+1}over2})。
其次就是期望也就是得分的状态转移的方程了:
假如这一位是(o)的话,那么(f[i])就是相当与上一位为(x),这一位为(x+1),那么变化量也就是(2x+1),所以状态转移方程就是
假如这一位是(x)的话,那么得分也就是不变了,只需要把(g[i])改成(0)即可,状态转移方程就是
第三种就是(?)的情况,因为每种情况都是(0.5)的概率,所以状态转移方程就很好想了,就是
按这三个进行状态转移就行了,下边是代码。
代码
#include<bits/stdc++.h>
const int maxn = 3e5+10;
int n;
double f[maxn];
double g[maxn];
char ch[maxn];
int 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;
}