题意:
给你n个数,每次只能让一个数+1,或者-1,目标是最终使这个序列构成一个非递减的序列;
n是5e3,复杂度n^2内。值是1e9;
思路:
可以发现子结构是保证一个区间的非递减,
如果只是dp[a][b]代表在[a,b]上需要的最小步数,这样很难处理a,b位置的值,且不构成递推性;
所以可以在递推中(前i个)去dp以 j 值为末端的区间需要的最小步数。
dp[i][j]=min(dp[i][j],min(dp[i][k]+cost); //k∈[1-j];
然而j值是1e9,且特么n是5e3都好大啊;如果小点就好做了。
看了题解上面的方法可以离散化搞一搞,可是好麻烦。
有一个结论:变化后的每一个值肯定是等于原来序列的某个值。
那么变化后我们知道是非递减的,所以问题就转变为a数组变成b数组求一个最小花费;
dp[i][j]为a序列前i个以b[j]结尾的b序列的最小花费
#include<cstdio>
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N=5e3+10;
int a[N];
int b[N];
LL dp[N];
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b,b+n);
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++){
for(int j=0;j<n;j++)
{
dp[j]+=abs(a[i]-b[j]);
if(j)
dp[j]=min(dp[j-1],dp[j]);
}
}
printf("%I64d
",dp[n-1]);
return 0;
}