code vs 2188 最长上升子序列(线段树优化DP)
2016-08-04 21:04
776 查看
2188 最长上升子序列
时间限制: 1 s空间限制: 32000 KB
题目等级 : 钻石 Diamond
题解
查看运行结果
题目描述 Description
LIS问题是最经典的动态规划基础问题之一。如果要求一个满足一定条件的最长上升子序列,你还能解决吗?
给出一个长度为N整数序列,请求出它的包含第K个元素的最长上升子序列。
例如:对于长度为6的序列<2,7,3,4,8,5>,它的最长上升子序列为<2,3,4,5>,但如果限制一定要包含第2个元素,那么满足此要求的最长上升子序列就只能是<2,7,8>了。
输入描述 Input Description
第一行为两个整数N,K,如上所述。
接下来是N个整数,描述一个序列。
输出描述 Output Description
请输出两个整数,即包含第K个元素的最长上升子序列长度。
样例输入 Sample Input
8 6
65 158 170 299 300 155 207 389
样例输出 Sample Output
4
数据范围及提示 Data Size & Hint
80%的数据,满足0<n<=1000,0<k<=n
100%的数据,满足0<n<=200000,0<k<=n
题解:线段树优化DP
把K之前小于K的值保留下来,K之后大于K的值保留下来,然后做最长上升子序列,就是这个题的答案,但是如果每次找当前点前面比这个点的值小的更新答案,时间复杂度n^2,所以我们可以把权值离散化,然后建立一颗权值线段树,来维护f[i]的值,每次更新的时候只需要求出这个点在权值线段树中之前点的最大值即可,0(n log n )
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define N 2000003 using namespace std; int n,k,a ,f ,num ,cnt,mark; int b ,q ,tr[N*8]; int cmp(int x,int y) { return num[x]<num[y]; } void update(int now) { tr[now]=max(tr[now<<1],tr[now<<1|1]); } void pointchange(int now,int l,int r,int x,int v) { if (l==r) { tr[now]=max(tr[now],v); return; } int mid=(l+r)/2; if (x<=mid) pointchange(now<<1,l,mid,x,v); else pointchange(now<<1|1,mid+1,r,x,v); update(now); } int qjmax(int now,int l,int r,int ll,int rr) { if (l>=ll&&r<=rr) return tr[now]; int mid=(l+r)/2; int maxn=0; if (ll<=mid) maxn=max(maxn,qjmax(now<<1,l,mid,ll,rr)); if (rr>mid) maxn=max(maxn,qjmax(now<<1|1,mid+1,r,ll,rr)); return maxn; } int main() { freopen("a.in","r",stdin); freopen("my.out","w",stdout); scanf("%d%d",&n,&k); for (int i=1;i<=n;i++) scanf("%d",&a[i]); for (int i=1;i<=n;i++) { if (a[i]<a[k]&&k>i) num[++cnt]=a[i]; if (a[i]>a[k]&&k<i) num[++cnt]=a[i]; if (k==i) num[++cnt]=a[i],mark=cnt; b[cnt]=cnt; } sort(b+1,b+cnt+1,cmp); int sz=0; num[b[0]]=1000000000; for (int i=1;i<=cnt;i++) if (num[b[i]]!=num[b[i-1]]) q[b[i]]=++sz; else q[b[i]]=sz; f[1]=1; pointchange(1,0,sz,q[1],f[1]); for (int i=2;i<=cnt;i++) { if (q[i]!=1) f[i]=qjmax(1,0,sz,0,q[i]-1)+1; else f[i]=1; pointchange(1,0,sz,q[i],f[i]); } int ans=0; for (int i=mark;i<=cnt;i++) ans=max(ans,f[i]); printf("%d\n",ans); }
相关文章推荐
- codevs 2188 最长上升子序列(DP)
- 【基础练习】【线性DP】codevs1576 最长严格上升子序列题解
- codevs 2188 最长上升子序列
- Codevs 2188 最长上升子序列
- 【基础练习】【二分】codevs2188 最长上升子序列(限定元素)题解
- CODE[VS] 最长公共上升子序列(LCIS)(序列型DP)
- Codevs P2188 最长上升子序列
- Codevs 2188 最长上升子序列 dp
- 【基础练习】【线性DP】codevs1576 最长严格上升子序列题解
- 最长上升子序列nlogn通解(dp之线段树优化)
- codevs 1576 最长严格上升子序列
- [codevs1576] 最长严格上升子序列
- CODEVS 1576最长严格上升子序列
- 最长公共上升子序列的DP解法及其优化
- 最长公共上升子序列(codevs 2185)
- codevs 3955 最长严格上升子序列(加强版)(DP)
- codevs 1576最长严格上升子序列
- Codevs 2188 最长上升子序列(变式)
- codevs1044 拦截导弹(最长不下降子序列dp)
- codevs1044 拦截导弹(最长不下降子序列dp)