個人認爲這道題和收集郵票或多或少有相似的地方。
它們都有一個特點,就是某一步產生的貢獻和這一步的信息有關。
解決分兩步:第一步,計算步長的期望。第二步,找到不同步長之間貢獻差值的關係式。
切入點:先假設每一步的貢獻都是。
然後遞推出步長的貢獻後,用找到的關係式去計算真實的貢獻。
用表示以第位結尾的連續的期望長度。
用表示到第位爲止的期望分數。
那麼對於,這一段對應的貢獻就是。(根據題中定義)
如果已知,假設第位就是,那麼這時候有
當前的貢獻就是
而原來的貢獻是,發現這時增加了。當然,如果這一位是貢獻就是。如果是,就用對應情況的概率*對應情況的期望就好了。這樣就可以直接遞推了。
現在考慮轉移。
如果當前位置爲,那麼這很顯然,因爲這裏的貢獻爲嘛
如果當前位置爲,那麼根據剛纔推導的式子可以得出。
如果當前位置爲,那麼用對應情況的概率*對應情況的期望。有和兩種可能。那麼
最後答案就是。
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
double l[maxn],f[maxn];
int n;char ch[maxn];
int main(){
scanf("%d%s",&n,ch+1);
for(int i=1;i<=n;++i){
if(ch[i]=='x') f[i]=f[i-1],l[i]=0;
if(ch[i]=='o') f[i]=f[i-1]+2.0*l[i-1]+1.0,l[i]=l[i-1]+1.0;
if(ch[i]=='?') f[i]=f[i-1]+l[i-1]+0.5,l[i]=(l[i-1]+1.0)/2.0;
}printf("%.4lf",f[n]);
}
當然,只是一個關係的形式,只要找到關係,怎麼寫都可以,像下面這樣。
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
double l[maxn],f[maxn];
int n;char ch[maxn];
int main(){
scanf("%d%s",&n,ch+1);
for(int i=1;i<=n;++i){
if(ch[i]=='x')
f[i]=f[i-1],l[i]=0;
if(ch[i]=='o')
l[i]=l[i-1]+1.0,f[i]=f[i-1]-l[i-1]*l[i-1]+l[i]*l[i];
if(ch[i]=='?')
f[i]=f[i-1]+((l[i-1]+1)*(l[i-1]+1)-l[i-1]*l[i-1])/2.0,
l[i]=(l[i-1]+1.0)/2.0;
}printf("%.4lf",f[n]);
}