Codevs2188最长上升子序列题解

来源:互联网 发布:京东淘宝区别是什么 编辑:程序博客网 时间:2024/06/06 02:06
  • 题目描述 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<n10000<kn
    100%的数据,满足0<n2000000<kn

  • 题解
    首先,要求最长上升子序列中必须有第K个,那么K前面的比K大的元素一定不在所求子序列中,K后面比K小的也不在。所以预处理:先把K前面的比K大的元素和K后面比K小的元素全部删去,这样K一定在新序列的最长上升子序列中。然后在新得到的序列上做O(nlog2n)的最长严格上升子序列即可。

  • Code

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int maxn = 200010;int n, k, a[maxn], b[maxn], tot;int s[maxn], top;void init(){    int x = 0;    scanf("%d%d", &n, &k);    for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);    for(int i = 1; i < k; ++i)    {        if(a[i] < a[k]) b[++tot] = a[i];    }    b[++tot] = a[k];    for(int i = k + 1; i <= n; ++i)    {        if(a[i] > a[k]) b[++tot] = a[i];    }}void work(){    for(int i = 1; i <= tot; ++i)    {        if(b[i] > s[top]) s[++top] = b[i];        else        {            int l = 1, r = top, mid;            while(l <= r)            {                mid = (l >> 1) + (r >> 1) + (l & r & 1);                if(s[mid] < b[i]) l = mid + 1;                else r = mid - 1;            }            s[l] = b[i];        }    }    printf("%d", top);}int main(){    init();    work();    return 0; }

  • 第一个对拍程序,珍藏:
@echo off:loop    rand.exe > data.txt    Codevs2188.exe < data.txt > std.txt    Codevs2188最长上升子序列.exe < data.txt > ans.txt    fc /A std.txt ans.txt    if not errorlevel 1 goto loop    pause:end
0 0