HDU3507 Print Article
http://acm.hdu.edu.cn/showproblem.php?pid=3507
斜率优化\(DP\)
\[dp_i=\min \{dp_j+(s_i-s_j)^2+m)\}\\
若j优于k(j>k)\\
dp_j+(s_i-s_j)^2+m)<dp_k+(s_i-s_k)^2+m)\\
dp_j+s_j^2-dp_k-s_k^2<2s_i(s_j-s_k)\\
\frac{dp_j+s_j^2-dp_k-s_k^2}{2(s_j-s_k)}<s_i\\
\]
单调队列尾部的\(r\)可以通过画图来判断什么时候应当左移(本题中维护的是上凸壳)
\(C++ Code:\)
#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 500005
#define ll long long
int n,m;
int q[N];
ll c[N],s[N],dp[N];
using namespace std;
#define x(a,b) (2LL*(s[a]-s[b]))
#define y(a,b) (dp[a]+s[a]*s[a]-dp[b]-s[b]*s[b])
int main()
{
while (scanf("%d%d",&n,&m)!=EOF)
{
for (int i=0;i<=n;i++)
s[i]=dp[i]=0;
for (int i=1;i<=n;i++)
{
scanf("%lld",&c[i]);
s[i]=s[i-1]+c[i];
}
int l=1,r=1;
q[r]=0;
#define j q[r]
#define k q[l]
for (int i=1;i<=n;i++)
{
while (l<r && y(q[l+1],q[l])<=x(q[l+1],q[l])*s[i])
l++;
dp[i]=dp[k]+(s[i]-s[k])*(s[i]-s[k])+m;
while (l<r && y(q[r],q[r-1])*x(i,q[r])>=y(i,q[r])*x(q[r],q[r-1]))
r--;
r++;
q[r]=i;
}
printf("%lld\n",dp[n]);
}
return 0;
}