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\n",dp[n]); } return 0; }