Acwing 273. 分级
题意:
给定一个长度为N的序列A,现在构造一个长度为N的序列B,满足,B是非严格单增。最小化S=∑i=1N∣Ai−Bi∣\sum_{i=1}^{N}|A_i-B_i|∑i=1N∣Ai−Bi∣
题解:
引理:
一定存在一组最优解,使得每个Bi都是原序列中的某个值
这个引理是题目的关键
证明:
证明了来自y总
A’[]是已经排序的数组a
剩下就简单:dp[i][j]:表示前i个数已经分配好了b的第i个数我们赋值为A′[j]A'[j]A′[j]的最小S值
dp[i][j]=min(dp[i-1][j])+abs(a[i]-A’[j])
为什么A’[]是排序的?因为B数组是非严格递增或递减的,排序后取才能保证
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>using namespace std;const int N = 2010, INF = 0x3f3f3f3f;int n;
int a[N], b[N];
int f[N][N];int work()
{for (int i = 1; i <= n; i ++ ) b[i] = a[i];sort(b + 1, b + n + 1);for (int i = 1; i <= n; i ++ ){int minv = INF;for (int j = 1; j <= n; j ++ ){minv = min(minv, f[i - 1][j]);f[i][j] = minv + abs(a[i] - b[j]);}}int res = INF;for (int i = 1; i <= n; i ++ ) res = min(res, f[n][i]);return res;
}int main()
{scanf("%d", &n);for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);int res = work();reverse(a + 1, a + n + 1);res = min(res, work());printf("%d\n", res);return 0;
}