最近,Farmer John的奶牛們愈來愈不滿於牛棚裏一塌糊塗的電話服務因而,她們要求FJ把那些老舊的電話線換成性能更好的新電話線。 新的電話線架設在已有的N(2 <= N <= 100,000)根電話線杆上, 第i根電話線杆的高度爲height_i米(1 <= height_i <= 100)。電話線老是從一根電話線杆的頂端被引到相鄰的那根的頂端 若是這兩根電話線杆的高度不一樣,那麼FJ就必須爲此支付 C*電話線杆高度差(1 <= C <= 100)的費用。固然,你不能移動電話線杆,只能按原有的順序在相鄰杆間架設電話線。Farmer John認爲 加高某些電話線杆能減小架設電話線的總花費,儘管這項工做也須要支出必定的費用。更準確地,若是他把一根電話線杆加高X米的話,他得爲此付出X^2的費用。請你幫Farmer John計算一下,若是合理地進行這兩種工做,他最少要在這個電話線改造工程上花多少錢。ios
設計dp狀態爲 \(dp[i][j]\) 表示考慮前 \(i\) 個柱子, 而且將第 \(i\) 個柱子的高度改造爲 \(j\) 的最小花費
容易想出 \(dp\) 方程: \[dp[i][j] = min(dp[i - 1][k] + (j - h[i])^{2} + |j - k| * c)\]
複雜度 \(O(nC_{2})\)
考慮優化
發現絕對值比較難處理
咱們先把無關 \(k\) 的值提出來, 分類討論處理一下絕對值
\[dp[i][j] = min(dp[i - 1][k] - c * k) + (j - h[i])^{2} + c * j\ \ \ (j \geq k)\]
\[dp[i][j] = min(dp[i - 1][k] + c * k) + (j - h[i])^{2} - c * j\ \ \ (j \leq k)\]性能
而後 \(min\) 裏能夠用一個變量維護
處理絕對值分別正序倒敘枚舉便可優化
#include<iostream> #include<cstdio> #include<queue> #include<cstring> #include<algorithm> #include<climits> #define LL long long #define REP(i, x, y) for(LL i = (x);i <= (y);i++) using namespace std; LL RD(){ LL out = 0,flag = 1;char c = getchar(); while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();} while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();} return flag * out; } const LL maxn = 200019, inf = 0xfffffffffffffff; LL num, c, h[maxn]; LL dp[maxn][119]; LL maxx; void init(){ num = RD(), c = RD(); REP(i, 1, num)h[i] = RD(), maxx = max(maxx, h[i]); REP(i, 0, num)REP(j, 0, maxx)dp[i][j] = inf; } void solve(){ REP(i, h[1], maxx)dp[1][i] = (h[1] - i) * (h[1] - i); REP(i, 2, num){ LL minn = inf; REP(j, h[i - 1], maxx){ minn = min(minn, dp[i - 1][j] - j * c); if(j < h[i])continue; LL add = (j - h[i]) * (j - h[i]); dp[i][j] = min(dp[i][j], minn + add + j * c); } minn = inf; for(int j = maxx;j >= h[i];j--){ minn = min(minn, dp[i - 1][j] + j * c); LL add = (j - h[i]) * (j - h[i]); dp[i][j] = min(dp[i][j], minn + add - j * c); } } LL ans = inf; REP(i, h[num], maxx)ans = min(ans, dp[num][i]); printf("%lld\n", ans); } int main(){ init(); solve(); return 0; }