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