NC16810 [NOIP1999]拦截导弹

题目链接

题目

题目描述

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

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

输入描述

1行,若干个整数(个数≤100000)

输出描述

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

示例1

输入

389 207 155 300 299 170 158 65

输出

6
2

题解

知识点:线性dp。

第一问没什么好说的,一个最长不上升子序列。

第二问用到dilworth定理:最长上升子序列的划分数 = 最长不上升子序列的长度。手玩理解一下就好,具体证明可以百度qwq。

这里要求最长不上升子序列的划分数,也就是求LCS的长度。

时间复杂度 \(O(n^2)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>

using namespace std;

int a[100007], dp[100007];

int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n = 0;
    while (cin >> a[n++]);
    n--;
    for (int i = 0;i < n;i++) {
        dp[i] = 1;
        for (int j = 0;j < i;j++)
            if (a[i] <= a[j]) dp[i] = max(dp[i], dp[j] + 1);
    }
    int ans = 0;
    for (int i = 0;i < n;i++) ans = max(ans, dp[i]);
    cout << ans << '\n';
    for (int i = 0;i < n;i++) {
        dp[i] = 1;
        for (int j = 0;j < i;j++)
            if (a[i] > a[j]) dp[i] = max(dp[i], dp[j] + 1);
    }
    ans = 0;
    for (int i = 0;i < n;i++) ans = max(ans, dp[i]);
    cout << ans << '\n';
    return 0;
}
posted @ 2022-08-11 21:33  空白菌  阅读(33)  评论(0编辑  收藏  举报