这道题特别坑
状态转移是 f[i][k+1]=f[j][k]+(sum[i]-sum[j])*(sum[i]-sum[j]);
转换后变为 f[j][k]+sum[j]*sum[j]=f[i][k+1]+2*sum[i]*sum[j];
但是我在这里要说的是一个初值的问题
通常情况下斜率优化的题目都是不需要赋初值的
但因为f[i][1]全都为0,所以导致后续dp值全部出错
所以我们应将f[i][2]赋上初值为sum[i]*sum[i]
总体实现如下:
#include <algorithm> #include <iostream> #include <cmath> #include <cstring> #include <map> #include <string> #include <vector> #include <queue> #include <stack> #include <cstdio> #include <cstdlib> using namespace std; typedef long long ll; inline ll read() { register ll p(1),a(0);register char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-') ch=getchar(); if(ch=='-') p=-1,ch=getchar(); while(ch>='0'&&ch<='9') a=a*10+ch-48,ch=getchar(); return a*p; } //f[i][k+1]=f[j][k]+(sum[i]-sum[j])*(sum[i]-sum[j]); //f[j][k]+sum[j]*sum[j]=f[i][k+1]+2*sum[i]*sum[j]; const ll N=3010; ll n,kk,f[N][N],sum[N],Q[N],head=0,tail=0; inline double getx(int x){return sum[x];} inline double gety(int x,int now){return f[x][now]+sum[x]*sum[x];} inline double che(int x,int y,int now){return (gety(y,now)-gety(x,now))/(getx(y)-getx(x));} int main() { // freopen("input","r",stdin); // freopen("output","w",stdout); n=read(),kk=read(); for(register int i=1;i<=n;i++) sum[i]=sum[i-1]+read(),f[i][2]=sum[i]*sum[i]; for(register int k=2;k<=kk;k++,head=tail=0) for(register int i=1,j;i<=n;i++) { while(head<tail&&che(Q[head],Q[head+1],k)<2*sum[i]) ++head; j=Q[head];f[i][k+1]=f[j][k]+(sum[i]-sum[j])*(sum[i]-sum[j]); while(head<tail&&che(Q[tail-1],Q[tail],k)>che(Q[tail],i,k)) --tail; Q[++tail]=i; } printf("%lld ",f[n][kk+1]*kk-sum[n]*sum[n]); return 0; } /* */