设序列 a 1 , a 2 , a 3 , a 4 , . . . , a n a_1,a_2,a_3,a_4,...,a_n a1,a2,a3,a4,...,an 的平均值为 x x x,权值和为 t o t tot tot,方差 S = ∑ i = 1 n ( a i − x ) 2 n S = \displaystyle\frac{\displaystyle\sum_{i = 1}^n(a_i -x)^2}{n} S=ni=1∑n(ai−x)2
乘上 n 2 n^2 n2 得到: S = ∑ i = 1 n ( m ∗ a i − t o t ) 2 n S = \displaystyle\frac{\displaystyle\sum_{i = 1}^n(m*a_i -tot)^2}{n} S=ni=1∑n(m∗ai−tot)2
统计分子部分,最后再除以 n。
题目转化过来就是将 n 个数分成 m 段,使得最后 S S S 尽可能小。
每一段对 S S S 的分子部分的贡献不难计算,考虑 dp,dp[i][j] 表示前 i 个数分成 j 段对 S 的最小贡献
,答案显然为 dp[n][m]
转移方程: d p [ i ] [ t ] = min j = 1 i ( d p [ j ] [ t − 1 ] + ( m ∗ ( s u m [ i ] − s u m [ j ] ) − t o t ) 2 ) dp[i][t] = \displaystyle\min_{j = 1}^i(dp[j][t - 1] + (m * (sum[i] - sum[j]) - tot)^2) dp[i][t]=j=1mini(dp[j][t−1]+(m∗(sum[i]−sum[j])−tot)2)
注意初值,对所有的 i < j , d p [ i ] [ j ] = i n f i <j,dp[i][j] = inf i<j,dp[i][j]=inf
直接做的复杂度是 n 2 m n^2m n2m,考虑优化,将式子展开可以得到:
d p [ i ] [ t ] = min j = 1 i ( d p [ j ] [ t − 1 ] + m 2 ∗ s u m [ i ] 2 + m 2 ∗ s u m [ j ] 2 − 2 m 2 ∗ s u m [ i ] ∗ s u m [ j ] + t o t 2 − 2 m ∗ t o t ∗ s u m [ i ] + 2 ∗ m ∗ t o t ∗ s u m [ j ] ) dp[i][t] = \displaystyle\min_{j = 1}^i(dp[j][t - 1] + m^2*sum[i]^2+m^2*sum[j]^2-2m^2*sum[i]*sum[j]+tot^2-2m*tot*sum[i]+2*m*tot*sum[j]) dp[i][t]=j=1mini(dp[j][t−1]+m2∗sum[i]2+m2∗sum[j]2−2m2∗sum[i]∗sum[j]+tot2−2m∗tot∗sum[i]+2∗m∗tot∗sum[j])
出现了 2 m 2 ∗ s u m [ i ] ∗ s u m [ j ] 2m^2*sum[i]*sum[j] 2m2∗sum[i]∗sum[j],考虑斜率优化,斜率为 2 m ∗ s u m [ i ] 2m*sum[i] 2m∗sum[i] (移项后的斜率),斜率单调递增,要求 d p [ i ] [ t ] dp[i][t] dp[i][t] 最小值,维护下凸包。
设 j > k j > k j>k,在 j j j 点比在 k k k 点转移更优,则满足 :
d p [ j ] [ t − 1 ] + m 2 ∗ s u m [ i ] 2 + m 2 ∗ s u m [ j ] 2 − 2 m 2 ∗ s u m [ i ] ∗ s u m [ j ] + t o t 2 − 2 m ∗ t o t ∗ s u m [ i ] + 2 ∗ m ∗ t o t ∗ s u m [ j ] dp[j][t - 1] + m^2*sum[i]^2+m^2*sum[j]^2-2m^2*sum[i]*sum[j]+tot^2-2m*tot*sum[i]+2*m*tot*sum[j] dp[j][t−1]+m2∗sum[i]2+m2∗sum[j]2−2m2∗sum[i]∗sum[j]+tot2−2m∗tot∗sum[i]+2∗m∗tot∗sum[j] < < <
d p [ k ] [ t − 1 ] + m 2 ∗ s u m [ i ] 2 + m 2 ∗ s u m [ k ] 2 − 2 m 2 ∗ s u m [ i ] ∗ s u m [ k ] + t o t 2 − 2 m ∗ t o t ∗ s u m [ i ] + 2 ∗ m ∗ t o t ∗ s u m [ k ] dp[k][t - 1] + m^2*sum[i]^2+m^2*sum[k]^2-2m^2*sum[i]*sum[k]+tot^2 -2m*tot*sum[i]+2*m*tot*sum[k] dp[k][t−1]+m2∗sum[i]2+m2∗sum[k]2−2m2∗sum[i]∗sum[k]+tot2−2m∗tot∗sum[i]+2∗m∗tot∗sum[k]
式子非常长,后面一段就是把 j 换成 k,消掉相同的并进行移项化简,最后可以得到:
令 c [ i ] [ t ] = d p [ i ] [ t ] + m 2 ∗ s u m [ i ] 2 + 2 m ∗ t o t ∗ s u m [ i ] c[i][t] = dp[i][t] + m^2*sum[i]^2 + 2m*tot*sum[i] c[i][t]=dp[i][t]+m2∗sum[i]2+2m∗tot∗sum[i]
代入得: c [ j ] [ t − 1 ] − c [ k ] [ t − 1 ] s u m [ j ] − s u m [ t ] < 2 m ∗ s u m [ i ] \displaystyle\frac{c[j][t - 1] - c[k][t - 1]}{sum[j] - sum[t]} < 2m*sum[i] sum[j]−sum[t]c[j][t−1]−c[k][t−1]<2m∗sum[i]
用单调队列维护 c [ j ] [ t − 1 ] − c [ k ] [ t − 1 ] s u m [ j ] − s u m [ t ] \displaystyle\frac{c[j][t - 1] - c[k][t - 1]}{sum[j] - sum[t]} sum[j]−sum[t]c[j][t−1]−c[k][t−1] 单增,根据决策单调性寻找最优转移点,复杂度降为 O ( n ∗ m ) O(n*m) O(n∗m)
对第二维可以进行滚动,最后答案要记得除以 m。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e3 + 10;
typedef long long ll;
const ll inf = 1e17;
int n,N;
ll sum[maxn],dp[maxn],tp[maxn],c[maxn],m[5],tot;
int q[maxn],front,rear;
ll calc(int x,int y) {
ll tmp = m[1] * (sum[x] - sum[y]) - tot;
return tp[y] + tmp * tmp;
}
int main() {
scanf("%d%d",&n,&m[1]);
for (int i = 2; i <= 4; i++)
m[i] = 1ll * m[i - 1] * m[1];
for (int i = 1,x; i <= n; i++)
scanf("%d",&sum[i]);
for (int i = 1; i <= n; i++)
sum[i] += sum[i - 1];
tot = sum[n];
for (int j = 1; j <= n; j++)
tp[j] = dp[j] = inf;
for (int t = 1; t <= m[1]; t++) {
front = rear = 0;
q[++rear] = t - 1;
for (int i = t; i <= n; i++) {
while (front + 1 < rear && calc(i,q[front + 1]) >= calc(i,q[front + 2]))
front++;
dp[i] = calc(i,q[front + 1]);
while (front + 1 < rear && (c[i] - c[q[rear]]) * (sum[q[rear]] - sum[q[rear - 1]])
<= (c[q[rear]] - c[q[rear - 1]]) * (sum[i] - sum[q[rear]]))
rear--;
q[++rear] = i;
}
for (int i = 0; i <= n; i++) {
tp[i] = dp[i];
c[i] = tp[i] + m[2] * sum[i] * sum[i] + 2 * m[1] * tot * sum[i];
dp[i] = inf;
}
}
printf("%lld\n",tp[n] / m[1]);
return 0;
}