hdu 3507 Print Article(斜率优化dp入门题)

题意:输入n个数字,将其分成几组,每一组算出其和的平方加上m,将每一组的值求和,求这个和的最小值

dp方程:dp[i]=min{dp[j]+(S[i]S[j])^2+m}(j<i)

这里要用斜率来优化才能用单调队列

这篇博客讲的很不错了:https://www.cnblogs.com/orzzz/p/7885971.html

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxx = 500010;
int q[maxx];//存下标
LL sum[maxx],dp[maxx];
//dp[i]=min(dp[j]+m+(sum[i]-sum[j])^2)
int n,m;
LL getup(int j,int k)
{
    return dp[j]+sum[j]*sum[j]-(dp[k]+sum[k]*sum[k]);
}
LL getdown(int j,int k)
{
    return sum[j]-sum[k];
}
LL getdp(int i,int j)
{
    return dp[j]+m+(sum[i]-sum[j])*(sum[i]-sum[j]);
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        LL t;
        dp[0]=sum[0]=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&t);
            sum[i]=sum[i-1]+t;
        }
        int l=1,r=1;
        q[r]=0;
        for(int i=1;i<=n;i++)
        {
            while(l+1<=r&&getup(q[l+1],q[l])<=2*sum[i]*getdown(q[l+1],q[l]))l++;
            dp[i]=getdp(i,q[l]);
            //维护下凸
            while(l+1<=r&&getup(i,q[r])*getdown(q[r],q[r-1])<=getup(q[r],q[r-1])*getdown(i,q[r]))r--;
            q[++r]=i;
        }
        printf("%lld
",dp[n]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/HooYing/p/10951343.html