1. 程式人生 > 實用技巧 >BZOJ-3450 Tyvj1952 Easy(概率dp)

BZOJ-3450 Tyvj1952 Easy(概率dp)

題目描述

  有一個長為 \(n(n\leq 3\times 10^5)\) 的字串,有的字元是 o,有的字元是 x,有的字元是 ?,表示 ox 各有 \(50\%\) 的可能性,分數是按 \(comb\) 計算的,連續 \(a\)\(comb\) 就有 \(a^2\) 分,\(comb\) 就是極大的連續 o

  求字串的期望得分。

分析

  設 \(dp[i]\) 為以第 \(i\) 位為結尾的連續 o 的期望長度。

  若 \(s_i=o,dp[i]=dp[i-1]+1\);若 \(s_i=x,dp[i]=0\);若 \(s_i=?,dp[i]=\frac{dp[i-1]+1}{2}\)

  由於 \(E(aX+bY)=aE(X)+bE(Y)\),因此每一段連續 o 是相互獨立、互不影響的,在維護期望長度的同時計算每一位的貢獻:

  若 \(s_i=o\),連續 o 的長度從 \(i-1\) 變成 \(i\),貢獻比原來增加了 \((dp[i-1]+1)^2-(dp[i-1])^2=2\times dp[i-1]+1\)

  若 \(s_i=x\),無貢獻。

  若 \(s_i=?\),有 \(\frac{1}{2}\) 的概率長度增加至 \(dp[i-1]+1\),貢獻增加了 \(\frac{1}{2}\times ((dp[i-1]+1)^2-(dp[i-1])^2)=dp[i-1]+\frac{1}{2}\)

程式碼

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
double dp[N];
char s[N];
int main()
{
    int n;
    cin>>n;
    cin>>(s+1);
    dp[0]=0;
    double ans=0;
    for(int i=1;i<=n;i++)
    {
        if(s[i]=='o')
        {
            dp[i]=dp[i-1]+1;
            ans=ans+2*dp[i-1]+1;
        }
        if(s[i]=='x')
            dp[i]=0;
        if(s[i]=='?')
        {
            dp[i]=0.5*(dp[i-1]+1);
            ans=ans+(dp[i-1]+0.5);
        }
    }
    printf("%.4lf\n",ans);
    return 0;
}