bzoj1049 [HAOI2006]数字序列 ( LIS + 区间DP)
来源:互联网 发布:淘宝首页在线制作 编辑:程序博客网 时间:2024/06/09 20:39
bzoj1049 [HAOI2006]数字序列
原题地址:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1049
题意:
现在我们有一个长度为n的整数序列A。但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列。
但是不希望改变过多的数,也不希望改变的幅度太大。
求:
1.最少需要改变多少个数
2.在改变的数最少的情况下,每个数改变的绝对值之和的最小值。
数据范围
n<=35000,保证所有数列是随机的。
题解:
ydc神犇的题解
神题,神结论。
O(n^3)水过随机数据。
首先对于第一问,求最少需要改变多少个数:
补集转化的思想,即求 n-(最多有多少个数不改变),
就是求最长严格上升子序列长度,用二分+单调栈即可。
(但是这里有一个转化,就是 数字-标号,转为求最长不降子序列,在第二问中有用)
对于第二问:
之前在第一问中,每个数都 数字-标号,转为求最长不降子序列了,之后得到一个f[i]数组
f[i]表示,以i结尾的最长不降子序列长度。
设 g[i]=以i结尾的最长不降子序列,从1到i,要全部转为不降的最小代价。
那么怎么求g[i]呢?
考虑最原始的求解最长不降子序列的方法。
是一个n^2的DP,f[i]由前面最大的f[j]+1满足 a[j]<=a[i]转移过来。
就是说,取i的前一个保留位置是j,( i,j )区间的全部都要改变使[i,j]不降。
于是得到一个转移方程:
令w[i,j]表示保留i,j,使区间[i,j]合法的最小代价。
g[i]=min( g[j]+w[j,i] ) ( f[i]==f[j]+1 且 a[i]>=a[j] )
w[i,j]怎么算?
有一个非常重要的结论:
对于[i+1,j]区间,必然存在一个断点m,使得如果让 i+1到m-1都变成 i,m到j都变成 j ,是保留i,j,使区间[i,j]合法的最小代价。
证明见ydc神犇
于是w[i,j]就可以枚举断点来求。
总复杂度 O(n^3) ,本来是会T的,
但是对于找到 f[i]==f[j]+1 且 a[i]>=a[j] 时,可以把 f[i]=x预先存下来,因为数列是随机的,可以水过。
代码:
#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<vector>#define LL long longusing namespace std;const int N=36000;const int inf=0x3f3f3f3f;int n,stack[N],top=0,a[N],f[N];LL g[N],s1[N],s2[N];vector<int> V[N];int find(int x){ int lf=1; int rg=top; while(lf+1<rg) { int mid=(lf+rg)>>1; if(stack[mid]<=x) lf=mid; else rg=mid; } if(stack[lf]>x) return lf; else return rg;}int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) {scanf("%d",&a[i]); a[i]=a[i]-i;} for(int i=1;i<=n;i++) { if(top==0||stack[top]<=a[i]) {stack[++top]=a[i];f[i]=top;} else if(stack[1]>a[i]) {stack[1]=a[i]; f[i]=1;} else {f[i]=find(a[i]);stack[f[i]]=a[i];} V[f[i]].push_back(i); } printf("%d\n",n-top); for(int i=0;i<=n+1;i++) g[i]=1LL<<60; V[0].push_back(0); a[0]=-inf; g[0]=0; V[top+1].push_back(n+1); a[n+1]=inf; f[n+1]=top+1; for(int i=1;i<=n+1;i++) { int sz=V[f[i]-1].size(); for(int j=0;j<sz;j++) { int x=V[f[i]-1][j]; if(x>i) break; if(a[x]>a[i]) continue; s1[x]=s2[x]=0; for(int k=x+1;k<=i;k++) { s1[k]=abs(a[x]-a[k]); s2[k]=abs(a[i]-a[k]); } for(int k=x+1;k<=i;k++) { s1[k]=s1[k-1]+s1[k]; s2[k]=s2[k-1]+s2[k]; } for(int k=x+1;k<=i;k++) g[i]=min(g[i],g[x]+s1[k-1]-s1[x]+s2[i]-s2[k-1]); } } printf("%I64d\n",g[n+1]); return 0;}
- bzoj1049 [HAOI2006]数字序列 ( LIS + 区间DP)
- [BZOJ1049][HAOI2006]数字序列(dp)
- 【bzoj1049】【HAOI2006】【数字序列】【dp+暴力】
- [bzoj1049][HAOI2006]数字序列
- bzoj1049: [HAOI2006]数字序列
- BZOJ1049: [HAOI2006]数字序列
- bzoj1049 [HAOI2006]数字序列
- bzoj1049: [HAOI2006]数字序列
- BZOJ1049 数字序列 [DP]
- bzoj1049 数字序列
- BZOJ 1049([HAOI2006]数字序列-数字序列LIS与分块)
- 1049: [HAOI2006]数字序列
- BZOJ 1049: [HAOI2006]数字序列
- 【BZOJ 1049】 [HAOI2006]数字序列
- [bzoj 1049] HAOI2006数字序列
- bzoj 1049 [HAOI2006]数字序列
- BZOJ 1049: [HAOI2006]数字序列
- [bzoj] 1049: [HAOI2006]数字序列
- 20171103
- 阿里云的OSS对象存储 java
- 三齿轮问题:三个齿轮啮合
- LeetCode 654. Maximum Binary Tree
- 经典排序算法
- bzoj1049 [HAOI2006]数字序列 ( LIS + 区间DP)
- SpringBoot自动配置的实现原理
- 前序 中序 后序遍历
- 项目管理心得:一个项目经理的个人体会、经验总结
- 爆搜dfs
- Scikit-learn安装教程
- 我为什么喜欢跑步
- mybatis 报错 Result Maps collection already contains value for BaseResultMap
- REST接口