定义状态为前i个数字形成的以数字j结尾的单调序列的最小花费
有如下状态转移方程
经过化简可得
可以用滚动数组实现
时间复杂度是O(N*1e9)
空间复杂度是O(1e9)
两个复杂度都太高了。注意到n远远小于1e9,所以想到离散化。(当然我是想不到)
离散化的方法就是将n个数字和1-n对应起来
我们dp的时候其实是不用dp出1e9的所有数据的,我们只需要dp出这n个数据的答案就行了。
所以最后复杂度为O(N * N)
看了大佬的博客知道POJ题目有bug,不需要算递减序列的情况。
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX_N 2005
#define INF 0x3f3f3f3f
using namespace std;
typedef long long int ll;
ll Abs(ll a)
{
return a < 0 ? -a : a;
}
int main()
{
//freopen("1.txt", "r", stdin);
ll N, a[MAX_N], b[MAX_N];
while (cin >> N)
{
for (ll i = 1; i <= N; i++)
{
scanf("%I64d", &a[i]);
b[i] = a[i];
}
sort(b + 1, b + N + 1);
ll dp[MAX_N];
memset(dp, 0, sizeof(dp));
for (ll i = 1; i <= N; i++)
for (ll j = 1; j <= N; j++)
{
if (j == 1)
dp[j] = dp[j] + Abs(a[i] - b[j]);
else
dp[j] = min(dp[j - 1], dp[j] + Abs(a[i] - b[j]));
}
ll ans = INF;
for (int i = 1; i <= N; i++)
ans = min(ans, dp[N]);
printf("%I64d\n", ans);
}
return 0;
}