P1020 导弹拦截(最长不上升序列+二分)

题目链接

题目描述

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。

输入导弹依次飞来的高度(雷达给出的高度数据是 ≤50000 \le 50000≤50000 的正整数),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入输出格式
输入格式:

111 行,若干个整数(个数 ≤100000 \le 100000≤100000 )

输出格式:

222 行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

输入:

389 207 155 300 299 170 158 65

输出:

6
2

思路

一个序列最少有多少个不上升子序列 = 这个序列最长上升子序列的长度
每次上升都是一次转折

AC

#include <bits/stdc++.h>
#define N 100005
using namespace std;
int a[N], b[N];
int main() {
    // freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(false);
    int n = 0, t;
    while(cin >> t) {
        a[++n] = t;
    }
    int len1 = 0;
    b[0] = 0x3f3f3f3f;
    for (int i = 1; i <= n; i++) {
        if (a[i] <= b[len1])    b[++len1] = a[i];
        else {
            int seat = upper_bound(b + 1, b + 1 + len1, a[i], greater<int>()) - b;
            b[seat] = a[i];
        }
    }
    cout << len1 << endl;
    b[0] = -1;
    int len2 = 0;
    for (int i = 1; i <= n; i++) {
        if (a[i] > b[len2]) b[++len2] = a[i];
        else {
            int seat = lower_bound(b + 1, b + 1 + len2, a[i]) - b;
            b[seat] = a[i];
        }
    }
    cout << len2 << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/henuyh/article/details/80758765