POJ_3666

    由于递增和递减是类似的,下面不妨只讨论变成递增序列的情况。

    我们可以用f[i][j]表示递推到第i个数时,将第i个数变成<=j且满足序列是非减的所需要的最小的代价。由于j的范围较大,可以先离散化,不妨设最后一共有S个不同的数,那么我们要计算的就是f[N][S]。

    可以得到f[i][j]=std::min(f[i-1][j]+abs(...),f[i][j-1]),式子中的...表示省略了一部分内容。如果还想优化空间的话,用滚动数组实现即可。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXD 5010
typedef long long LL;
int N, S, a[MAXD], rank[MAXD];
LL f[MAXD];
struct Di
{
    int id, v;
    bool operator < (const Di &t) const
    {
        return v < t.v;
    }
}di[MAXD];
LL deal()
{
    int i, j;
    for(i = 1; i <= N; i ++) di[i].id = i, di[i].v = a[i];
    std::sort(di + 1, di + 1 + N);
    rank[di[1].id] = S = 1;
    for(i = 2; i <= N; i ++)
    {
        if(di[i].v != di[i - 1].v) di[++ S].v = di[i].v;
        rank[di[i].id] = S;
    }
    memset(f, 0, sizeof(f));
    for(i = 1; i <= N; i ++)
    {
        f[0] = 0x3f3f3f3f3f3f3f3fll;
        for(j = 1; j <= S; j ++)
            f[j] = std::min(f[j - 1], f[j] + std::abs(a[i] - di[j].v));
    }
    return f[S];
}
void solve()
{
    int i;
    LL ans = deal();
    for(i = 1; i <= N / 2; i ++) std::swap(a[i], a[N - i + 1]);
    ans = std::min(ans, deal());
    printf("%lld\n", ans);
}
int main()
{
    while(scanf("%d", &N) == 1)
    {
        for(int i = 1; i <= N; i ++) scanf("%d", &a[i]);
        solve();
    }
    return 0;
}

 

 

 

posted on 2012-09-28 12:17  Staginner  阅读(816)  评论(0编辑  收藏  举报