当前位置:首页 > 提高组 > 1999年NOIP提高组导弹拦截(洛谷P1020)解题思路与动态规划代码解析

1999年NOIP提高组导弹拦截(洛谷P1020)解题思路与动态规划代码解析

6个月前 (06-18)

1999年NOIP提高组导弹拦截(洛谷P1020)解题思路与动态规划代码解析  动态规划 最长上升子序列 最长下降子序列 NOIP提高组 第1张

一、题目解读

    1999年NOIP提高组“导弹拦截”问题(对应洛谷P1020)要求设计导弹拦截系统:给定一组导弹高度数据,需计算最少拦截系统数量,并求最多能拦截的导弹数。核心难点在于将问题转化为最长不上升子序列(第一问)与最长上升子序列(第二问)的求解,考验动态规划与序列分析能力。

二、解题思路

采用动态规划+二分查找优化策略:

    1. 第一问:最长不上升子序列(LDS)——维护一个存储当前最长LDS末尾元素的数组dp,通过upper_bound(从大到小查找第一个大于目标值的迭代器)动态更新,确保序列严格不上升。

    2. 第二问:最长上升子序列(LIS)——类似思路,利用lower_bound(从小到大查找第一个大于等于目标值的迭代器)维护LIS末尾,得到拦截系统数量。

    两者时间复杂度均为O(nlogn),避免暴力枚举

三、解题步骤

1. 数据输入:循环读入导弹高度,存入missiles向量。

2. LDS求解:遍历导弹高度,通过upper_bound在dp中查找可替换的末尾元素(若未找到则扩展序列),最终dp.size()即为拦截数。

3. LIS求解:同理用lower_bound更新tails数组,其大小即为所需系统数量。

4. 输出结果:两问答案分别对应LDS长度与LIS长度。

四、代码与注释

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); // 加速IO

    vector<int> missiles; // 存储导弹高度
    int height;
    
    // 高效读取输入数据
    while (cin >> height) {
        missiles.push_back(height);
    }
    
    int n = missiles.size();
    
    // 第一问:O(nlogn)求最长不上升子序列
    vector<int> dp; // 存储LDS末尾元素
    for (int h : missiles) {
        auto it = upper_bound(dp.begin(), dp.end(), h, greater<int>()); // 从大到小查找第一个大于h的位置
        if (it == dp.end()) { // 若未找到,扩展序列
            dp.push_back(h);
        } else {
            *it = h; // 替换末尾元素(缩短序列长度)
        }
    }
    int max_intercept = dp.size(); // LDS长度即拦截数
    
    // 第二问:O(nlogn)求最长上升子序列
    vector<int> tails; // 存储LIS末尾元素
    for (int h : missiles) {
        auto it = lower_bound(tails.begin(), tails.end(), h); // 从小到大查找第一个大于等于h的位置
        if (it == tails.end()) {
            tails.push_back(h);
        } else {
            *it = h; // 替换末尾元素(优化序列长度)
        }
    }
    int system_count = tails.size(); // LIS长度即系统数量
    
    cout << max_intercept << "\n" << system_count << "\n";
    return 0;
}

五、总结

    本解法巧妙将导弹拦截问题转化为经典动态规划模型(LIS/LDS),并通过二分查找函数大幅优化效率。代码简洁且逻辑清晰,体现了“问题转化”与“算法优化”在竞赛编程中的重要性。掌握此类技巧,能有效应对涉及序列极值统计的复杂场景。



原创内容 转载请注明出处

分享给朋友:

相关文章

CSP-J方格取数题解|动态规划解法|洛谷P7074代码解析

CSP-J方格取数题解|动态规划解法|洛谷P7074代码解析

一、题目解读题目要求在一个n×m的网格中,从左上角到右下角选择一条路径,路径上的数字可重复取用,求取数之和的最大值。路径限制为仅能向右或向下移动。需注意路径的灵活性与重复取数的可能性,传统单向动态规划...

牛客12576题解题全解析:动态规划+质因数分解实现跳跃问题最优解

牛客12576题解题全解析:动态规划+质因数分解实现跳跃问题最优解

一、题目解读牛客12576题是一道经典的算法题,要求给定起点N和终点M,求解从N到M的最少跳跃次数。题目考察的核心在于路径优化与动态规划思想,需结合数论中的质因数分解技巧,通过合理设计算法降低时间复杂...

2017年 NOIP 提高组 逛公园(洛谷P3953)题解:代码解析与优化

2017年 NOIP 提高组 逛公园(洛谷P3953)题解:代码解析与优化

一、题目解读    2017年NOIP提高组“逛公园”题目(洛谷P3953)要求在有向图中计算从起点到终点满足特定条件的路径数量。题目难点在于处理路径长度限制与...

洛谷2789题解:直线交点数的递归求解与优化(附代码详解)

洛谷2789题解:直线交点数的递归求解与优化(附代码详解)

一、题目解读洛谷2789题要求计算n条直线在平面上两两相交时产生的不同交点数量。题目强调“不同”交点,需排除重复情况。解题关键在于如何高效枚举所有可能的交点组合,并避免重复计数。二、解题思路参考代码采...

洛谷P4999题解析:动态规划求解数字拆分与求和问题(附代码)

洛谷P4999题解析:动态规划求解数字拆分与求和问题(附代码)

一、题目解读洛谷P4999题要求处理给定区间 [L, R] 内数字的拆分与求和问题。每个数字需拆分为其各位数字之和,并计算区间内所有数字之和的累加结果。题目需考虑大数情况,并采用取模运算(MOD=1e...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。