您的位置:首页 > 其它

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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: