个人认为这道题和收集邮票或多或少有相似的地方。
它们都有一个特点,就是某一步产生的贡献和这一步的信息有关。
解决分两步:第一步,计算步长的期望。第二步,找到不同步长之间贡献差值的关系式。
切入点:先假设每一步的贡献都是。
然后递推出步长的贡献后,用找到的关系式去计算真实的贡献。
用表示以第位结尾的连续的期望长度。
用表示到第位为止的期望分数。
那么对于,这一段对应的贡献就是。(根据题中定义)
如果已知,假设第位就是,那么这时候有
当前的贡献就是
而原来的贡献是,发现这时增加了。当然,如果这一位是贡献就是。如果是,就用对应情况的概率*对应情况的期望就好了。这样就可以直接递推了。
现在考虑转移。
如果当前位置为,那么这很显然,因为这里的贡献为嘛
如果当前位置为,那么根据刚才推导的式子可以得出。
如果当前位置为,那么用对应情况的概率*对应情况的期望。有和两种可能。那么
最后答案就是。
#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]);
}