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;
}
posted @ 2020-12-08 21:00  Tartarus_li  阅读(65)  评论(0编辑  收藏  举报