Vijos-p1369 难解的问题(LIS优化代码)

难解的问题

描述

在你的帮助下,蔚蓝来到了埃及.在金字塔里,蔚蓝看到了一个问题,传说,能回答出这个问题的人就能受到埃及法老的祝福,可是蔚蓝日夜奋战,还是想不出来,你能帮帮他么?(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项的最长上升子序列的长度.

样例1

样例输入1

5 3
1 2 3 2 1

样例输出1

3

限制

各个测试点1s

提示

对于60%的数据,N<=10000;
对于100%的数据,1<=n<=300000 ,1<=k<=n,序列的每一个数为小于2^31-1 的非负整数.

解题

第K项将序列分成两份,左边算出小于第K项的LIS长度len1,有边算出大于第K项的LIS长度len2,结果就是len1 + len2 + 1

代码

#include <algorithm>  //P1369 难解的问题
#include <iostream>
#include <string>
using namespace std;
const int maxn = 3e5 + 2;
int num[maxn];
int dp[maxn];

int up_bound(int l, int r, int x) {
    
    
    while (l < r) {
    
    
        int mid = (l + r) / 2;
        if (dp[mid] < x) {
    
    
            l = mid + 1;
        } else {
    
    
            r = mid;
        }
    }
    return l;
}

int main() {
    
    
    int N, K;
    cin >> N >> K;
    for (int i = 1; i <= N; i++) scanf("%d", &num[i]);

    int len1 = 0;  //优化从0开始计数, 不从1开始
    dp[len1] = 0;
    for (int i = 1; i < K; i++) {
    
    
        if (num[i] < num[K]) {
    
    
            if (num[i] > dp[len1]) {
    
    
                dp[++len1] = num[i];
            } else {
    
    
                int up = up_bound(1, len1, num[i]);
                dp[up] = num[i];
            }
        }
    }

    int len2 = 0;
    dp[len2] = 0;
    for (int i = K + 1; i <= N; i++) {
    
    
        if (num[i] > num[K]) {
    
    
            if (num[i] > dp[len2]) {
    
    
                dp[++len2] = num[i];
            } else {
    
    
                int up = up_bound(1, len2, num[i]);
                dp[up] = num[i];
            }
        }
    }

    cout << len1 + len2 + 1 << endl;

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45349225/article/details/109693057