【BZOJ 1049】 1049: [HAOI2006]数字序列 (LIS+动态规划)

1049: [HAOI2006]数字序列

Description

  现在我们有一个长度为n的整数序列A。但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列。
但是不希望改变过多的数,也不希望改变的幅度太大。

Input

  第一行包含一个数n,接下来n个整数按顺序描述每一项的键值。n<=35000,保证所有数列是随机的

Output

  第一行一个整数表示最少需要改变多少个数。 第二行一个整数,表示在改变的数最少的情况下,每个数改变
的绝对值之和的最小值。

Sample Input

4
5 2 3 5

Sample Output

1
4

HINT

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 }
View Code

 

2017-01-17 10:33:31

posted @ 2017-01-17 10:27  konjak魔芋  阅读(199)  评论(0编辑  收藏  举报