CodeForces 13C【DP】

题意:
给你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;
}
原文地址:https://www.cnblogs.com/keyboarder-zsq/p/5934852.html