题目
思路
这是一道人类智慧题;果然我不配做人!
最 n a i v e \rm naive naive 的想法是 O ( n 2 ) \mathcal O(n^2) O(n2) 的 d p \tt dp dp 求出每一个小段的期望经过次数。没找到优化点。
我们是不是应该考虑一下 距离是等差 这个别有用心的设计?——没错,就是 “别有用心” 而不是 “别具匠心”。
本来 d p \tt dp dp 就是递归子问题,但是它更彻底。设原距离数组是 a x = d x + b a_x=dx{+}b ax=dx+b,考虑进行一次操作后,剩下的长度为 ( 2 n − 2 ) (2n{\rm -}2) (2n−2) 的距离数组的每一项的 期望值(就是概率乘长度的和嘛,相当于在递归中的贡献系数)。
为了方便,可以忽略 “球” 和 “洞” 的身份,笼统说为 “相邻元素可同时删去”。那么,对于第 x ( 1 ⩽ x ⩽ 2 n − 2 ) x\;(1\leqslant x\leqslant 2n{-}2) x(1⩽x⩽2n−2) 项,若删去前面 a y ( 1 ⩽ y ⩽ x ) a_y\;(1\leqslant y\leqslant x) ay(1⩽y⩽x) 的左右端点,则 a y a_y ay 会再拓展 2 2 2 个区间,使得 a x ′ = a x + 2 a'_x=a_{x+2} ax′=ax+2(顺次补齐两个空洞)。概率是 x 2 n x\over 2n 2nx 。
若删去
a
x
+
1
a_{x+1}
ax+1 的左右端点则
a
x
′
=
a
x
+
a
x
+
1
+
a
x
+
2
a'_x=a_x+a_{x+1}+a_{x+2}
ax′=ax+ax+1+ax+2,概率是
1
2
n
1\over 2n
2n1 。其他情况下
a
x
′
=
a
x
a'_x=a_x
ax′=ax,概率是
2
n
−
x
−
1
2
n
{2n-x-1\over 2n}
2n2n−x−1 。三者相加,得到新期望长度
a
x
′
=
x
a
x
+
2
+
3
a
x
+
1
+
(
2
n
−
x
−
1
)
a
x
2
n
=
(
2
n
−
1
)
a
x
+
2
d
x
+
3
a
x
+
1
2
n
\begin{aligned} a'_x &=\frac{xa_{x+2}+3a_{x+1}+(2n{-}x{-}1)a_x}{2n}\\[1ex] &=\frac{(2n{-}1)a_x+2dx+3a_{x+1}}{2n} \end{aligned}
ax′=2nxax+2+3ax+1+(2n−x−1)ax=2n(2n−1)ax+2dx+3ax+1
于是 a x ′ − a x − 1 ′ = ( 2 n − 1 ) d + 2 d + 3 d 2 n = n + 2 n d a'_{x}-a'_{x-1}=\frac{(2n-1)d+2d+3d}{2n}=\frac{n+2}{n}d ax′−ax−1′=2n(2n−1)d+2d+3d=nn+2d 为常数。新的期望距离仍然是等差数列!
所以,我们递归到一个 a x = n + 2 n d x + b ′ a_x=\frac{n+2}{n}dx+b' ax=nn+2dx+b′ 的情况,仍然可以用上面的方法计算。现在只需要快速求出第一次操作提供的贡献。
第一次操作时,每个距离都可以被等概率选中;期望应为 ∑ a i 2 n = a 1 + a 2 n 2 \frac{\sum a_i}{2n}={a_1+a_{2n}\over 2} 2n∑ai=2a1+a2n,等差数列的平均值嘛。每次 O ( 1 ) \mathcal O(1) O(1),时间复杂度就 O ( n ) \mathcal O(n) O(n) 了。
代码
极度舒适的代码 😎
#include <cstdio>
int main(){
int n; double ans, head, d;
scanf("%d %lf %lf",&n,&head,&d);
for(ans=0; n; d=d*(n+2)/n,--n){
ans += head+((n<<1)-1)*d/2;
head += (2*head+5*d)/(n<<1);
}
printf("%.12f\n",ans);
return 0;
}