Description
Input
Output
首先能够很简单的得到DP方程:
dpi=min(dpj+Func(sumi−sumj))
设有 j ,
dpj−dpk+a∗sum2j−a∗sum2k+b∗(sumk−sumj)−2a∗(sumj−sumk)∗sumi>0
移项得:
(fj−fk+a∗(sum2j−sum2k)+b∗(sumk−sumj))/(2a∗(sumj−sumk))>sumi
设
fj+a∗sum2j−b∗sumj=yj
fk+a∗sum2k−b∗sumk=yk
2a∗sumj=xj
2a∗sumj=xk
就得到了:
(yj−yk)/(xj−xk)>sumi
这就是斜率,用单调队列维护即可。
#include <cstdio>
#include <cstdlib>
#include <iostream>
#define sqr(x) ((x) * (x))
#define N 1000010
using namespace std;
typedef long long ll;
ll sum[N], dp[N];
int q[N], x[N];
int h = 0, t = 0, a, b, c, n;
inline char get(void) {
static char buf[1000000], *p1 = buf, *p2 = buf;
if (p1 == p2) {
p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin);
if (p1 == p2) return EOF;
}
return *p1++;
}
inline void read(int &x) {
x = 0; char c = get(); int sign = 1;
for (; c < '0' || c > '9'; c = get()) if(c == '-') sign = 0;
for (; c >= '0' && c <= '9'; x = (x << 1) + (x << 3) + c - '0', c = get());
x = sign ? x : -x;
}
inline double slope(int k, int j) {
return (double)(dp[j] - dp[k] + a * (sqr(sum[j]) - sqr(sum[k])) + b * (sum[k] - sum[j]))
/ (double)(2 * a *(sum[j] - sum[k]));
}
inline ll Func(ll x) {
return a * sqr(x) + b * x + c;
}
int main(void) {
read(n); read(a); read(b); read(c);
for (int i = 1; i <= n; i++) {
read(x[i]); sum[i] = sum[i - 1] + x[i];
}
for (int i = 1; i <= n; i++) {
while (h < t && slope(q[h], q[h + 1]) < sum[i]) h++;
int y = q[h];
dp[i] = dp[y] + Func(sum[i] - sum[y]);
while (h < t && slope(q[t - 1], q[t]) > slope(q[t], i)) t--;
q[++t] = i;
}
cout << dp[n] << endl;
return 0;
}