bzoj4518: [Sdoi2016]征途

第一眼看到这题的想法:这不就是一题傻逼DP吗。。。水经验

然而……诶诶诶DP怎么写

%了题解(还被嘲讽%题解比自己AC还多)原来是式子化简错了(囧orz,所以我不化简给你),菜啊。

然后写个斜率优化就行(懒得滚)。。记得开LL(搞得都不知道什么时候开了)

/*
k1<k2 且 k2优于k1

f[k1][j-1]+(s[i]-s[k1])*(s[i]-s[k1])  >=   f[k2][j-1]+(s[i]-s[k2])*(s[i]-s[k2])

f[k1][j-1]-2*s[i]*s[k1]+s[k1]^2  >=   f[k2][j-1]-2*s[i]*s[k2]+s[k2]^2

f[k1][j-1]-2*s[i]*s[k1]+s[k1]^2  >=   f[k2][j-1]-2*s[i]*s[k2]+s[k2]^2

( f[k1][j-1]+s[k1]^2 ) - ( f[k2][j-1]+s[k2]^2 ) >=  2*s[i]*s[k1]-2*s[i]*s[k2]

( f[k1][j-1]+s[k1]^2 ) - ( f[k2][j-1]+s[k2]^2 ) / (s[k1]-s[k2]) <= 2*s[i]
*/
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
int a[3100],s[31000],list[3100];
LL f[3100][3100];
LL X(int k,int j)
{
    return f[k][j-1]+s[k]*s[k];
}
int Y(int k)
{
    return s[k];
}
double slope(int k1,int k2,int j)
{
    return double(X(k1,j)-X(k2,j)) / double(Y(k1)-Y(k2));
}
int main()
{
    freopen("journey.in","r",stdin);
    freopen("journey.out","w",stdout);
    int n,m,sum=0;
    scanf("%d%d",&n,&m);
    s[0]=0;for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        s[i]=s[i-1]+a[i];
        sum+=a[i];
        f[i][1]=s[i]*s[i];
    }
    for(int j=2;j<=m;j++)
    {
        int head=1,tail=1;
        list[1]=j-1;
        for(int i=j;i<=n;i++)
        {
            while(head<tail&&slope(list[head],list[head+1],j)<=2*s[i])head++;
            int x=list[head];
            f[i][j]=f[x][j-1]+(s[i]-s[x])*(s[i]-s[x]);
            while(head<tail&&slope(list[tail-1],list[tail],j)>slope(list[tail],i,j))tail--;
            list[++tail]=i;
        }    
    }
    printf("%lld\n",f[n][m]*m-sum*sum);
    return 0;
}

 

posted @ 2017-10-11 08:15  AKCqhzdy  阅读(144)  评论(0编辑  收藏  举报