AcWing 273 分級 (dp)
阿新 • • 發佈:2020-12-08
https://www.acwing.com/problem/content/275/
可以用歸納法證明一定存在最優方案, \(B\) 中的數全在 \(A\) 中出現過
所以設 \(dp[i][j]\),表示已經構造好前 \(i\) 個數,第 \(i\) 個數為 \(j\) 的方案數,
\[dp[i][j] = max_{1\leq k \leq j} \{dp[i-1][k] + \mid A_i - j \mid \} \]直接轉移是 \(O(n^3)\) 的,而我們發現,第三層的轉移中,決策集合是不會減少的,所以記錄下字首/字尾最小值轉移即可
因為 \(B\) 既可能是遞增的也可能是遞減的,所以做兩遍即可
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<cmath> using namespace std; typedef long long ll; const int maxn = 2010; int n, q; int a[maxn], c[maxn], dp[maxn][maxn]; ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; } int main(){ n = read(); for(int i = 1 ; i <= n ; ++i) a[i] = read(), c[i] = a[i]; sort(c + 1, c + 1 + n); q = unique(c + 1, c + 1 + n) - c - 1; for(int i = 1 ; i <= n ; ++i) a[i] = lower_bound(c + 1, c + 1 + n, a[i]) - c; dp[0][0] = 0; for(int i = 1 ; i <= n ; ++i){ int mn = 1000000007; for(int j = 1 ; j <= q ; ++j){ mn = min(mn, dp[i - 1][j]); dp[i][j] = mn + abs(c[j] - c[a[i]]); } } int ans = 1000000007; for(int i = 1 ; i <= q ; ++i) ans = min(ans, dp[n][i]); dp[0][0] = 0; for(int i = 1 ; i <= n ; ++i){ int mn = 1000000007; for(int j = q ; j >= 1 ; --j){ mn = min(mn, dp[i - 1][j]); dp[i][j] = mn + abs(c[j] - c[a[i]]); } } for(int i = 1 ; i <= q ; ++i) ans = min(ans, dp[n][i]); printf("%d\n", ans); return 0; }