【BZOJ 1049】 1049: [HAOI2006]数字序列 (LIS+动态规划)
1049: [HAOI2006]数字序列
Description
现在我们有一个长度为n的整数序列A。但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列。
但是不希望改变过多的数,也不希望改变的幅度太大。Input
第一行包含一个数n,接下来n个整数按顺序描述每一项的键值。n<=35000,保证所有数列是随机的
Output
第一行一个整数表示最少需要改变多少个数。 第二行一个整数,表示在改变的数最少的情况下,每个数改变
的绝对值之和的最小值。Sample Input
4
5 2 3 5Sample Output
1
4HINT
Source
【分析】
首先先每个数减去标号,变成<=的问题。
第一问显然是LIS。用传统nlogn打法就好了。
第二问,明显DP转移方程为:
g[i]=min{g[j]+cost(j,i)|f[j]+1==f[i]}
问题还是求cost(j,i)
如果满足f[j]+1==f[i],那么中间的元一定要不>=a[i],要不<=a[j]。
画个图想一想就知道一定有一个最优解是前半部分等于a[j],后半部分等于a[i]。
本来以为这题和上一题BZOJ 1367有异曲同工之妙,事实上这题要简单很多的啊ORZ。。。
只要后面好好搞,其实随机数据没有n^3,所以可以过!!、
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 #define Maxn 35010 8 #define INF 0xfffffff 9 #define LL long long 10 11 int a[Maxn],f[Maxn],g[Maxn]; 12 int n; 13 14 int myabs(int x) {return x<0?-x:x;} 15 int mymin(int x,int y) {return x<y?x:y;} 16 LL mymin(LL x,LL y) {return x<y?x:y;} 17 18 int ffind(int l,int r,int x) 19 { 20 while(l<r) 21 { 22 int mid=(l+r+1)>>1; 23 if(g[mid]<=x) l=mid; 24 else r=mid-1; 25 } 26 return l; 27 } 28 29 void LIS() 30 { 31 int l=0,r=0; 32 g[0]=-INF; 33 for(int i=1;i<=n;i++) 34 { 35 if(a[i]>=g[r]) 36 { 37 g[++r]=a[i]; 38 f[i]=r; 39 } 40 else 41 { 42 int x=ffind(l,r,a[i]); 43 g[x+1]=a[i]; 44 f[i]=x+1; 45 } 46 } 47 printf("%d\n",n-r); 48 } 49 50 struct node 51 { 52 int x,y,next; 53 }t[Maxn];int len; 54 55 int first[Maxn]; 56 void ins(int x,int y) 57 { 58 t[++len].x=x;t[len].y=y; 59 t[len].next=first[x];first[x]=len; 60 } 61 62 LL h[Maxn],s1[Maxn],s2[Maxn]; 63 64 void get_ans() 65 { 66 len=0; 67 memset(first,0,sizeof(first)); 68 for(int i=0;i<=n;i++) 69 { 70 ins(f[i],i); 71 } 72 memset(h,127,sizeof(h)); 73 h[0]=0; 74 for(int i=1;i<=n;i++) 75 for(int j=first[f[i]-1];j;j=t[j].next) 76 { 77 int y=t[j].y; 78 if(y>i) continue; 79 if(a[y]>a[i]) continue; 80 s1[y]=0; 81 for(int k=y+1;k<i;k++) s1[k]=s1[k-1]+myabs(a[k]-a[y]); 82 s2[i]=0; 83 for(int k=i-1;k>y;k--) s2[k]=s2[k+1]+myabs(a[k]-a[i]); 84 for(int k=y;k<i;k++) h[i]=mymin(h[i],h[y]+s1[k]+s2[k+1]); 85 } 86 printf("%lld\n",h[n]); 87 } 88 89 int main() 90 { 91 scanf("%d",&n); 92 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 93 for(int i=1;i<=n;i++) a[i]-=i; 94 a[0]=-INF;a[++n]=INF; 95 LIS(); 96 get_ans(); 97 return 0; 98 }
2017-01-17 10:33:31