hdu 3507 斜率dp

传送门


设dp[i]表示输出前i个的最小费用,那么有如下的DP方程:


dp[i]= min{ dp[j]+(sum[i]-sum[j])^2 +M }  0<j<i


其中 sum[i]表示数字的前i项和。

#include<bits/stdc++.h>
using namespace std;

#define ll long long
#define mp make_pair
const int maxn = 5e5+10;

ll dp[maxn];

typedef pair <ll, ll> Line;
#define k first
#define b second
struct ConvexHull
{
    Line stk[maxn];
    int l, r;
    void init(){ l = r = 0; }
    //sz r - l  [l,r)

    bool cover(Line &a, Line &b, Line &c)
    {
        // line a and b cover line c
        return (a.k - b.k) * (b.b - c.b) >= (b.b - a.b) * (c.k - b.k);
        //  >= 下凸包 求最小值
        //  <= 上凸包 求最大值
    }

    void add(Line p)
    {
        while(r - l > 1 && cover(p,stk[r-2],stk[r-1]))r--;
        stk[r++] = p;
    }

    ll calc(ll x, Line l){ return l.k * x + l.b; }

    ll ask(ll x)
    {
        while(r - l > 1 && calc(x,stk[l+1]) <= calc(x,stk[l]))l++;
        return calc(x,stk[l]);
    }
}hull;

#undef k
#undef b

ll sq(ll x){ return x*x; }

ll v[maxn];
ll sum[maxn];
int n,m;
int T;
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        ll ans=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&v[i]);
            sum[i]=sum[i-1]+v[i];
        }
        hull.init();
        hull.add(mp(0,0));
        for(int _=1;_<=n;_++)
        {
            dp[_]=sq(sum[_])+m+hull.ask(sum[_]);//常数
            hull.add( mp(-2ll*sum[_],sq(sum[_])+dp[_]));//k b
        }
        printf("%lld\n",dp[n]);
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值