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; }