【题目描述】

给定一个序列,有些位置是 o ,有些位置是 x,还有些位置不确定(用 ? 表示,各有 0.5 的概率是 ox)。

定义 comb 为极大的连续 o ,一段长度为 $a$ 的 comb 的收益为 $a^2$,序列的收益为 comb 的收益总和。

求序列收益的期望。

【题目链接】

BZOJ 3450 Easy

【解题思路】

$$ (x + 1)^2 - x^2 = 2x + 1 $$

我们可以单独考虑每个位置的贡献(长度为 $x + 1$ 的连续 o 的最后一个位置的贡献为 $2x + 1$)。

因为贡献是长度的线性表达式,根据期望的线性性质,贡献的期望可由长度的期望得到。

设 $len(i)$ 表示以 $i$ 结尾的连续 o 的长度的期望。

分情况讨论:

当字符为 o 时,长度直接加一。

$len(i) = len(i - 1) + 1$,对答案的贡献为 $2 \times len(i - 1) + 1$

当字符为 x 时,直接成为 $0$。

$len(i) = 0$,对答案贡献为 $0$。

当字符为 ? 时,一半的概率长度加一,一半的概率直接成为 $0$。

$len(i) = \frac 1 2 \times (len(i - 1) + 1)$,对答案的贡献为 $\frac 1 2 \times (2 \times len(i - 1) + 1)$。

【AC代码】

#include <iostream>
#include <iomanip>
 
const int MAXN = 300000;
 
char str[MAXN + 1];
int n;
 
double exLen[MAXN + 1];
 
inline double solve(){
    double ans = 0;
    for(int i = 1; i <= n; i++){
        if(str[i - 1] == 'o'){
            ans += 2 * exLen[i - 1] + 1;
            exLen[i] = exLen[i - 1] + 1;
        } else if(str[i - 1] == 'x'){
            exLen[i] = 0;
        } else if(str[i - 1] == '?'){
            ans += (2 * exLen[i - 1] + 1) / 2;
            exLen[i] = (exLen[i - 1] + 1) / 2;
        } else{
            throw;
        }
    }
 
    return ans;
}
 
int main(){
    std::cin >> n >> str;
     
    std::cout.setf(std::ios::fixed);
    std::cout << std::setprecision(4) << solve() << std::endl;
 
    return 0;
}

就是这样咯~