洛谷4072 [SDOI2016]征途

题解 动态规划 动态规划-斜率优化DP 省选/NOI-
题目链接 编辑文章

题意

把 $N$ 个数分成 $M$ 段,要求每段和的方差尽可能小,求最小值。

$N\le 3000$ 。

题解

我这个辣鸡的错误解法

方程还是比较容易想到的,用 $f[i][j]$ 表示当前是第 $i$ 段,分到第 $j$ 个数的最优解,方程为:

$$f[i][j] = \min_{k=0}^{j-1} (f[i-1][k] + \sum_{p=k+1}^j M\times (X_p - \overline {X})^2)$$

然后我就硬着头皮继续化简。因为 $\times M^2$ 后把每一项拆出来还是可能出现非整数,所以我就再 $\times M$ ,最后除掉就行了。

看起来有 $i$ 和 $j$ 相乘的项,所以往斜率优化去化简。用 $S_i$ 代表 $X_i$ 的前缀和,最后我写了两张草稿纸后得到了个又长又丑的式子:

$$M^2\times {S_k}^2 + f[i-1][k] = (2\times M^2\times S_j-w\times M\times S_n)\times S_k + (f[i][j]-M^2\times {S_j}^2 + 2\times M\times S_n\times S_j - {S_n}^2)$$

然后我悲催的发现 $(2\times M^2\times S_j-w\times M\times S_n)$ 虽然满足单调性,但可能是负的,不能用斜率优化,$GG$ 。

正解

$s^2$ 表示方差,$V_i$ 表示每一段的和,则

$$s^2M^2 = M\sum_{i=1}^M V_i^2-(\sum_{i=1}^mV_i)^2$$

可以发现 $(\sum_{i=1}^mV_i)^2$ 是固定的,所以最小化 $\sum_{i=1}^M V_i^2$ 就行了。直接上方程:

$$f[i][j] = \min_{k=1}^{j-1} (f[i-1][k] + (S_j-S_k)^2)$$

$$f[i-1][k] + {S_k}^2 = 2S_j\times S_k + (f[i][j]-{S_j}^2)$$

斜率 $2S_j$ 递增。

#include<bits/stdc++.h>

using namespace std;

inline int read()
{
    char ch=getchar();
    int f=1,x=0;
    while (ch<'0' || ch>'9')
    {
        if (ch=='-') f=-1;
        ch=getchar();
    }
    while (ch>='0' && ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return f*x;
}

int n,m,p,sum,s[3005],f[3005][3005],q[3005];

signed main()
{
    n=read(); m=read();
    for (int i=1;i<=n;i++) s[i]=s[i-1]+read();
    for (int i=1;i<=n;i++) f[1][i]=s[i]*s[i];
    for (int i=2;i<=m;i++)
    {
        int l=1,r=1; q[l]=0;
        for (int j=1;j<=n;j++)
        {
            while (l<r && f[i-1][q[l+1]]+s[q[l+1]]*s[q[l+1]]-f[i-1][q[l]]-s[q[l]]*s[q[l]]
                   <=(s[q[l+1]]-s[q[l]])*2*s[j]) l++;
            f[i][j]=f[i-1][q[l]]+(s[j]-s[q[l]])*(s[j]-s[q[l]]);
            while (l<r && (f[i-1][q[r]]+s[q[r]]*s[q[r]]-f[i-1][q[r-1]]-s[q[r-1]]*s[q[r-1]])*(s[j]-s[q[r]])
                   >=((f[i-1][j]+s[j]*s[j]-f[i-1][q[r]])-s[q[r]]*s[q[r]])*(s[q[r]]-s[q[r-1]])) r--;
            q[++r]=j;
        }
    }
    return !printf("%d",m*f[m][n]-s[n]*s[n]);
}

新评论

称呼不能为空
邮箱格式不合法
网站格式不合法
内容不能为空