HDU - 3507 Print Article(斜率DP)
阿新 • • 發佈:2020-07-23
題意:給出N個單詞,每個單詞有個非負權值Ci,現在要將它們分成連續的若干段,每段的代價為此段單詞的權值和的平方,還要加一個常數M。現在想求出一個最優方案,使得總費用之和最小。
分析:斜率DP優化,DP轉移方程式為\(f[i] = min(f[j] + (sum[i] - sum[j])^{2} + m), (0 <= j < i)\),我們可以進行斜率DP優化,我們調整表示式為\(f[j] + sum[j]^{2} = 2 * sum[i] * sum[j] - sum[i] ^ {2} + f[i] - m\),假設\(f[i] + sum[j] ^ {2}\)為\(y\),\(2 * sum[j]\)
#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <vector> #include <algorithm> using namespace std; using LL = long long; const int N = 500005; int a[N]; LL f[N]; LL sum[N]; int q[N]; LL get_y(int x) { return f[x] + sum[x] * sum[x]; } int main() { int n, m; while (scanf("%d%d", &n, &m) != EOF) { for (int i = 1; i <= n; ++i) scanf("%d", &a[i]); for (int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + a[i]; int hh = 0, tt = 0; q[0] = 0; for (int i = 1; i <= n; ++i) { while (hh < tt && (get_y(q[hh + 1]) - get_y(q[hh])) <= (2 * sum[i] * (sum[q[hh + 1]] - sum[q[hh]]))) ++hh; int k = q[hh]; f[i] = f[k] + (sum[i] - sum[k]) * (sum[i] - sum[k]) + m; while (hh < tt && ((get_y(q[tt]) - get_y(q[tt - 1])) * 2 * (sum[i] - sum[q[tt]])) >= ((get_y(i) - get_y(q[tt])) * 2 * (sum[q[tt]] - sum[q[tt - 1]]))) --tt; q[++tt] = i; } printf("%lld\n", f[n]); } return 0; }