codevs 2188 最长上升子序列

题目描述 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

 

      传送门直达目的地

 

题解:清北第二套题的第二道题考试的时候写炸了,这引起我的反思,要复习一下最长上升子序列。然后就找了个最长上升子序列的题。这道题增加的一点难度是必须含有第k个元素。稍微进行一下修改即可。

        当查找的第k个元素时,由于必须包含k,所以k插入位置x即为此时找到的最长上升子序列的长度。因为f数组中f[x]以后的数都是在k之前出现的比k大的数。此是f[1]~f[x]为一固定的序列,不再发生变化。然后a数组往后查找时,若有比a[k]小的数,直接忽略不进行运算。就避免了f[1]~f[k]序列中的数发生变化。

 

#include<cstdio>
#include<iostream>
#define N  200100
using namespace std;
int n,k,len=1,l=0;
int a[N];
int f[N];
int erfen(int l,int r,int p)
{
    if (l>r) return l;
    int mid=(l+r)>>1;
    if (f[mid]<p) erfen(mid+1,r,p);
      else erfen(l,mid-1,p);
}
int main()
{
    scanf("%d%d",&n,&k);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    f[len]=a[1];
    for (int i=2;i<=n;i++)
      {
           if (i>k&&a[i]<a[k]) continue;//忽略比a[k]小的数 
           int bj;
           if (a[i]>f[len]) f[++len]=a[i],bj=len;
           else 
             bj=erfen(l,len,a[i]);
           if (bj>len) len=bj;
           f[bj]=a[i];
           if (i==k) l=len=bj;//长度进行更改 
      }
    printf("%d",len);
    return 0;
}
必须包含第k个元素

 

 

 

posted @ 2016-10-26 17:27  外婆桥  阅读(175)  评论(0编辑  收藏  举报