[SDOI2016]征途

这道题特别坑

状态转移是 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;
}
/*

*/
 
原文地址:https://www.cnblogs.com/cold-cold/p/10131510.html