vijos1369:难解的问题

描述

在你的帮助下,蔚蓝来到了埃及.在金字塔里,蔚蓝看到了一个问题,传说,能回答出这个问题的人就能受到埃及法老的祝福,可是蔚蓝日夜奋战,还是想不出来,你能帮帮他么?(XXX: 胡扯,教主怎么可能想不出来= _ =||)(WS这人说的=。=)
问题是这样的: 
给定一个序列<a1,a2,...,an>.求最长上升子序列(lis)p1<p2<...<pw满足a[p1]<a[p2]<...<a[pw]
例如65 158 170 299 300 155 207 389
LIS=<65,158,170,299,300,389>。

但是,现在还有一个附加条件:求出的最长上升子序列必须含有第K项。

比如,在上面的例子中,要求求出的最长上升子序列必须含有第6项,那么最长上升子序列就是:65 155 207 389。

格式

输入格式

第一行是用空格隔开的两个正整数N、K,含义同上所述.
第二行N个数,即给出的序列.

输出格式

仅有一个数,表示含有第K项的最长上升子序列的长度.

样例输入:
5 3
1 2 3 2 1
 
样例输出:
3
 
思路:将第k项左边大于等于第k项的去掉,左边小于等于第k项的去掉。
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN=300005;
const int INF=0x7fffffff;
int h[MAXN],n,k;
int a[MAXN],top;
int dp[MAXN];
int    lowbound(int l,int r,int val)
{
    while(r-l>1)
    {
        int mid=(l+r)/2;
        if(dp[mid]>=val)
        {
            r=mid;
        }
        else
        {
            l=mid;
        }
    }    
    return r;
}
int main()
{
    cin>>n>>k;
    k--;
    for(int i=0;i<n;i++)
    {
        cin>>h[i];
        dp[i]=INF;
    }
    for(int i=0;i<k;i++)
    {
        if(h[i]<h[k])
        {
            a[top++]=h[i];
        }
    }
    a[top++]=h[k];
    for(int j=k+1;j<n;j++)
    {
        if(h[j]>h[k])
        {
            a[top++]=h[j];
        }
    }
    for(int i=0;i<top;i++)
    {
        int p=lowbound(-1,top,a[i]);
        dp[p]=a[i];
    }
    int res=lowbound(-1,top,INF);
    cout<<res<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/program-ccc/p/5704347.html