推薦學習博客:https://www.cnblogs.com/orzzz/p/7885971.html
題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=3507
#include <bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define sqr(x) ((x)*(x))
#define ll long long
using namespace std;
const int N = 3e6+10000;
const int mod = 1e9;
int n,m;
ll s[N],sum[N],dp[N];
int Q[N];
ll Y(int i, int j) {return dp[j]+sqr(sum[j])-dp[i]-sqr(sum[i]);} //求Y的差
ll X(int i, int j) {return sum[j]-sum[i];} //求X的差
int main() {
while(cin>>n>>m) {
rep(i, 1, n) {
cin>>s[i];
sum[i] = sum[i-1] + s[i];
}
int l=1,r=1;
Q[1]=0;
dp[0]=0;
rep(i, 1, n) { //用相乘的方法判斷分數大小
while(l<r&&Y(Q[l],Q[l+1])<=2*sum[i]*X(Q[l],Q[l+1]))l++; //維護隊首(刪除非最優決策)
int x = Q[l]; //取出隊列中最優元素j
dp[i] = dp[x] + sqr(sum[i]-sum[x]) + m; //計算dp
while(l<r&&Y(Q[r],i)*X(Q[r-1],Q[r]) <= Y(Q[r-1],Q[r])*X(Q[r],i))r--; //維護隊尾(維護下凸包性質)
Q[++r]=i; //入隊
}
cout<<dp[n]<<endl;
}
return 0;
}