洛谷P1365
WJMZBMR打osu! / Easy
题目背景
原 维护队列 参见 P1903
题目描述
某一天WJMZBMR在打osu~~~但是他太弱逼了,有些地方完全靠运气:(
我们来简化一下这个游戏的规则
有 次点击要做,成功了就是 o
,失败了就是 x
,分数是按 combo 计算的,连续 个 combo 就有 分,combo 就是极大的连续 o
。
比如ooxxxxooooxxx
,分数就是 。
Sevenkplus 闲的慌就看他打了一盘,有些地方跟运气无关要么是 o
要么是 x
,有些地方 o
或者 x
各有 的可能性,用 ?
号来表示。
比如 oo?xx
就是一个可能的输入。
那么 WJMZBMR 这场 osu 的期望得分是多少呢?
比如 oo?xx
的话,?
是 o
的话就是 oooxx
(),是x的话就是 ooxxx
(),期望自然就是 了。
输入格式
第一行一个整数 (),表示点击的个数
接下来一个字符串,每个字符都是 o
,x
,?
中的一个
输出格式
一行一个浮点数表示答案
四舍五入到小数点后 位
如果害怕精度跪建议用 long double 或者 extended。
样例 #1
样例输入 #1
4
????
样例输出 #1
4.1250
思路
此题也是概率期望dp比较经典的题目,
主要要注意递推方程的写法
而且要明确期望的数学公式
之前我出错主要是因为以为能从长度的期望递推到答案的期望
显然是错误的想法
对于期望的递推要注意每种情况对它的贡献度,并且概率和为1
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N = 3e5 + 5;
long double dp[2];
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
string s;
cin >> s;
if(s[0] == '?'){
dp[0] = 0.5;
dp[1] = 0.5;
}
else if(s[0] == 'x'){
dp[0] = 0;
dp[1] = 0;
}
else if(s[0] == 'o'){
dp[0] = 1;
dp[1] = 1;
}
for(int i = 0;i < n - 1; i++){
if(s[i+1] == 'x'){
dp[0] = 0;
}
else if(s[i+1] == 'o'){
long double p = dp[0];
dp[0] += 1;
dp[1] += 2*p+1;
}
else if(s[i+1] == '?'){
long double p = dp[0];
dp[0] = (dp[0] + 1) / 2;
dp[1] += p + 0.5;
}
// cout << dp[1] << " " << dp[0] << endl;
}
cout << fixed << setprecision(4) << dp[1] << endl;
return 0;
}
// 0.5 0.5
// 1.5 0.75
// 2.75 0.875
// 4.125 0.9375