AcWing 273 分级 (dp)
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;
}