BZOJ1049 HAOI2006 数字序列 一般DP

题意:有一个长度为n的整数序列A,将其变为严格单增序列,求:1、最少需要改变多少个数  2、在改变的数最少的情况下,每个数改变的绝对值之和的最小值

题解:

第一问太水,a[i]-=i之后直接跑最长上升子序列即可。

第二问太神,完全没思路,正解

#include <cmath>
#include <cstdio>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int MAXN=35000+2;
struct HASH{
    int u;
    HASH *next;
    HASH(){}
    HASH(int _u,HASH *_next):u(_u),next(_next){};
}*table[MAXN],mem[MAXN];
int d[MAXN],cnt,a[MAXN],n,f[MAXN];
long long g[MAXN],sum1[MAXN],sum2[MAXN];

int main(){
    cin >> n;
    
    for (int i=1;i<=n;i++) scanf("%d",a+i),a[i]-=i,d[i]=INT_MAX>>1;

    for (int i=n;i>=0;i--){
        table[f[i]]=&(mem[cnt++]=HASH(i,table[f[i]]));
        g[i]=LONG_LONG_MAX>>1;
    }
    g[0]=0,a[0]=INT_MIN>>1;

    for (int i=1;i<=n;i++)
        for (HASH *p=table[f[i]-1];p;p=p->next){
            if (p->u>i) break;
            if (a[p->u]>a[i]) continue;

            for(int k=p->u;k<=i;k++) sum1[k]=abs(a[p->u]-a[k]),sum2[k]=abs(a[i]-a[k]);
            for(int k=p->u+1;k<=i;k++) sum1[k]+=sum1[k-1],sum2[k]+=sum2[k-1];
            for(int k=p->u;k<i;k++) g[i]=min(g[i],g[p->u]+sum1[k]-sum1[p->u]+sum2[i]-sum2[k]);
        }

    cout<<g[n]<<endl;

    return 0;
}
View Code

 

posted @ 2017-02-28 01:44  WDZRMPCBIT  阅读(130)  评论(0编辑  收藏  举报