题解 P4072 【[SDOI2016]征途】
首先,我们先把结果的表达式化简一下
假设第
那么
所以,我们只需要计算最小的
假设
为了方便,我们先预处理出
所以,我们就可以写出状态转移方程:
显然,这么做的时间复杂度太高了,我们需要进行优化
怎么优化呢?我们考虑
所以,我们就可以进行斜率优化了!
附上代码:
#include<cstdio>
int n,m,l,r;
long long a[3010],sum[3010],f[3010],fl[3010],q[3010];
long long K(int x,int y)
{
return (fl[y]-fl[x]+sum[y]*sum[y]-sum[x]*sum[x])/(sum[y]-sum[x]);
}
int main()
{
scanf("%d%d",&n,&m),sum[0]=0;
for(int i=1;i<=n;i++) scanf("%lld",&a[i]),sum[i]=sum[i-1]+a[i];
for(int i=1;i<=n;i++) fl[i]=sum[i]*sum[i];
for(int i=2;i<=m;i++){
l=r=1,q[l]=i-1;
for(int j=i;j<=n;j++){
while(l<r&&K(q[l],q[l+1])<2*sum[j]) l++;
f[j]=fl[q[l]]+(sum[j]-sum[q[l]])*(sum[j]-sum[q[l]]);
while(l<r&&K(q[r-1],q[r])>K(q[r],j)) r--;
q[++r]=j;
}
for(int j=1;j<=n;j++) fl[j]=f[j];
}
printf("%lld",m*f[n]-sum[n]*sum[n]);
}