[NOIP2021] 方差
WeLikeStudying · · 题解
- 多写题解从我做起。
- 勿做斜杠青年从我做起。
- 希望作者不要爆零。
题意
- 题目链接。
- 给定长度为
n 的非严格递增正整数数列,a_1,a_2,\cdots,a_n 。 - 每次可以选定一个
1< i< n ,把a_i 变成a_{i-1}+a_{i+1}-a_i 。 - 可以进行无限次操作,求可能的数列方差的最小值乘
n^2 的结果。 -
- 后面记
a_i 的最大值为A 。
思路
- 看到这么多限制就要想结论。
- 首先有一个被强调千万次的结论:设
\overline{x^2} 为a_1^2,a_2^2,\cdots ,a_n^2 的平均值,\overline{x} 为a_1,a_2,\cdots,a_n 的平均值,则s^2=\overline{x^2}-\overline{x}^2 。 - 具体可以在这道题中得到解释。
- 然后容易发现特殊性质:设
a_i' 为变化后的,a_i 为变化前的,则:a_i'-a_{i-1}=a_{i-1}+a_{i+1}-a_i-a_{i-1}=a_{i+1}-a_i a_{i+1}-a_i'=a_{i+1}-(a_{i-1}+a_{i+1}-a_i)=a_i-a_{i-1} - 也就是本质上相当于交换差分数组,也就是设
b_i=a_{i+1}-a_i ,相当于求任意交换b_i 后还原出a_i 的方差最小值。 - 有一个
O(n!) 的暴力可以立刻打出来。 - 暴力实现。
- 然后下一步就是思考。
- 忽然想起:方差是和中心偏离的程度,用来衡量一批数据的波动大小。
- 于是我们思考,数据会长什么样子,使得它趋近于某个值。
- 由于数列
a 始终是递增的,情况并不难想。 - 我们发现,当差分数组是这样的时候:(也就是存在
b_i 使得b_1\ge b_2\ge \cdots b_i 且b_i\le b_{i+1}\le\cdots\le b_{n-1} ) - 因为这个时候,整个
a 数列长这样(即趋近于中间的某个数): - 因为其它情况显然没有这个集中。
- 就是暴力也能弄出一个
O(n\cdot 2^n) 的算法吧。 - 基于性质的暴力实现。
- 不过这道题值域这么小找到性质就可以进行动态规划了。
- 先将差分数组排好序。
- 设
f(i,u,v,S) 为使用b_1,b_2,\cdots b_i 的差分数组,以中间为0 计算,左边已经下降到-u 右边已经上升到v ,总和为S 的情况下的平方和最小值。 - 有初始状态:
f(0,0,0,0)=0 。 - 有转移状态:
f(i,u,v,S)+(v+b_{i+1})^2\rightarrow f(i+1,u,v+b_{i+1},S+v+b_{i+1}) f(i,u,v,S)+(u+b_{i+1})^2\rightarrow f(i+1,u+b_{i+1},v,S-u-b_{i+1}) - 不过很容易发现这是不好的,比如
S<0 ,难以维护,发现只要v-u 相等可以一起算,比较好一点的做法是: - 设
f(i,j,S) 为使用b_1,b_2,\cdots b_i 的差分数组,以左侧为0 计算,右边已经上升到了j ,且数组总和为S 的数据平方和最小值。 - 有初始状态
f(0,0,0)=0 。 - 有转移状态:
f(i,j,S)+(j+b_{i+1})^2\rightarrow f(i+1,j+b_{i+1},S+j+b_{i+1}) \rightarrow f(i+1,j+b_{i+1},S+b_{i+1}\times (i+1)) - 然后惊喜地发现第二维可以消掉,设
s(x)=\sum_{i=0}^xb_i ,设f(i,S) 为使用b_1,b_2,\cdots b_i 的差分数组,以左侧为0 计算,数据总和为S 的数据平方和最小值,别笑,我真滴是这样一步步推的。 - 有初始状态:
f(0,0)=0 。 - 有转移状态:
f(i,S)+s^2(i+1)\rightarrow f(i,S+s(i+1)) f(i,S)+2\times b_{i+1}\times S+b_{i+1}^2\times(i+1)\rightarrow f(i,S+b_{i+1}\times (i+1)) - 发现
S\le n\cdot A 恒成立,因此时间复杂度和空间复杂度都是O(n^2\cdot A) 。 - 而
f(i,S) 中的S 开到i\cdot s(i) 即可。 - 代码实现。
- 滚动数组可以优化一维使得空间不太紧张。
- 代码实现。
- 就这么 AC 了,测试数据也太水了……吗?
- 思考一下当
n>A 的时候,b_i 数组的前面会有一大堆0 ,实际有效的转移个数不会超过A 。 - 所以更精确的时间复杂度是
O(n\cdot \min(n,A)\cdot A) ,空间复杂度是O(n\cdot A) ,可以通过本题。 - 加了这个细节,出题者还算用心。