方法麻烦了,简单方法见https://oi.men.ci/sdoi2016-journey/
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;
const ll inf=1e15;
ll dp[3005][3005],sum[3005];
int n,m,i,head,tail,q[30005];
ll getup(int j,int k)
{
return dp[i-1][j]-dp[i-1][k]+(ll)m*sum[j]*sum[j]-(ll)m*sum[k]*sum[k]+(ll)2*sum[n]*sum[j]-(ll)2*sum[n]*sum[k];
}
ll getdown(int j,int k)
{
return (ll)2*m*(sum[j]-sum[k]);
}
ll getdp(int j,int k)
{
return dp[i-1][k]+(ll)m*(sum[j]-sum[k])*(sum[j]-sum[k])-(ll)2*sum[n]*(sum[j]-sum[k]);
}
int main()
{
freopen("menci_journey.in","r",stdin);
freopen("menci_journey.out","w",stdout);
scanf("%d%d",&n,&m);
ll x;
for (i=1;i<=n;i++)
{
scanf("%lld",&x);
sum[i]=sum[i-1]+x;
}
for (i=0;i<=3000;i++)
for (int j=0;j<=3000;j++) dp[i][j]=inf;
dp[0][0]=0;
for (i=1;i<=m;i++)
{
head=tail=1;
q[1]=i-1;
for (int j=i;j<=n;j++)
{
while (head<tail && getup(q[head+1],q[head])<=sum[j]*getdown(q[head+1],q[head])) head++;
dp[i][j]=getdp(j,q[head]);
while (head<tail && getup(j,q[tail])*getdown(q[tail],q[tail-1])<=getup(q[tail],q[tail-1])*getdown(j,q[tail])) tail--;
q[++tail]=j;
}
}
printf("%lld",dp[m][n]+sum[n]*sum[n]);
return 0;
}
总结
1:其实对于题目所问的问题,我们尝试处理出数学模型,将其转化为数学公式,尝试化简,再转化成斜率优化的式子
2:之所以整体斜率优化写麻烦了,实际上是对于公式没有化到最简,由此发现数学推倒的重要性!!,对于有公式出现,注意学会化简,并且积累公式化简的技巧。