【BZOJ 1049】 1049: [HAOI2006]数字序列 (LIS+动态规划)
2017-01-17 10:27
399 查看
1049: [HAOI2006]数字序列
Description
现在我们有一个长度为n的整数序列A。但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列。但是不希望改变过多的数,也不希望改变的幅度太大。
Input
第一行包含一个数n,接下来n个整数按顺序描述每一项的键值。n<=35000,保证所有数列是随机的Output
第一行一个整数表示最少需要改变多少个数。 第二行一个整数,表示在改变的数最少的情况下,每个数改变的绝对值之和的最小值。
Sample Input
45 2 3 5
Sample Output
14
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]。
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 ); 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
相关文章推荐
- [BZOJ1049][HAOI2006]数字序列(dp)
- 【bzoj1049】【HAOI2006】【数字序列】
- BZOJ1049: [HAOI2006]数字序列
- BZOJ 1049: [HAOI2006]数字序列
- 【BZOJ 1049】 [HAOI2006]数字序列
- [bzoj1049][HAOI2006]数字序列
- BZOJ 1049([HAOI2006]数字序列-数字序列LIS与分块)
- bzoj 1049 [HAOI2006]数字序列
- bzoj1049 [HAOI2006]数字序列
- BZOJ1049 [HAOI2006]数字序列0
- BZOJ1049: [HAOI2006]数字序列
- bzoj 1049: [HAOI2006]数字序列【dp+二分+瞎搞】
- 【bzoj1049】[HAOI2006]数字序列
- 1049: [HAOI2006]数字序列 - BZOJ
- bzoj1049 [HAOI2006]数字序列 ( LIS + 区间DP)
- bzoj1049[HAOI2006]数字序列
- bzoj 1049: [HAOI2006]数字序列(DP+DP)
- [bzoj] 1049: [HAOI2006]数字序列
- 【bzoj1049】【HAOI2006】【数字序列】【dp+暴力】
- 【BZOJ】1049: [HAOI2006]数字序列(lis+特殊的技巧)