给定长度为N的序列A,构造一个长度为N的序列B,满足:
1、B非严格单调,即B1≤B2≤…≤BN或B1≥B2≥…≥BN。
2、最小化 S=∑Ni=1|Ai−Bi|。
只需要求出这个最小值S。
输入格式
第一行包含一个整数N。
接下来N行,每行包含一个整数Ai。
输出格式
输出一个整数,表示最小S值。
数据范围
1≤N≤2000,
1≤|Ai|≤109
输入样例:
7
1
3
2
4
5
3
9
输出样例:
3
先给一个长度为N的序列,在A中选取N个数,组成非严格单调的序列B,(这里是可以取重复的数字,一开始理解错误,以为不能取相同的数字,导致样例解释错误),求最小的S=∑Ni=1|Ai−Bi|
这里我们可以用一个dp[ i ][ j ]数组,表示处理了前 i 位的情况下,第 j 位的最小更改数,当Bi = j 时,S的值最小。
故我们可以得到我们的动态转移方程:
dp [ i ][ j ] = min{ dp[ i - 1][k] + | a[i] - j | }, (0 <= k <= j);
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <map>
#include <stack>
#define maxn 2005
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
int n;
int a[maxn],Bup[maxn],Bdown[maxn];
ll dpup[maxn][maxn],dpdown[maxn][maxn];
int cmp(int a, int b)
{
return a > b;
}
int main()
{
while(cin >> n)
{
memset(dpdown, 0, sizeof(dpdown));
memset(dpup, 0, sizeof(dpup));
for(int i = 1; i <= n; i ++)
{
cin >> a[i];
Bup[i] = a[i];
Bdown[i] = a[i];
}
sort(Bup + 1, Bup + 1 + n);
sort(Bdown + 1, Bdown + 1 + n, cmp);
for(int i = 1; i <= n; i ++)
{
ll minn = INF;
for(int j = 1; j <= n; j ++)
{
minn = min(minn, dpup[i - 1][j]);
dpup[i][j] = minn + fabs(a[i] - Bup[j]);
}
}
for(int i = 1; i <= n; i ++)
{
ll minn = INF;
for(int j = 1; j <= n; j ++)
{
minn = min(minn, dpdown[i - 1][j]);
dpdown[i][j] = minn + fabs(a[i] - Bdown[j]);
}
}
ll up = INF;
ll down = INF;
for(int i = 1; i <= n; i ++)
up = min(up, dpup[n][i]);
for(int i = 1; i <= n; i ++)
down = min(down, dpdown[n][i]);
ll ans = min(up, down);
cout << ans << endl;
}
return 0;
}