当前位置: 首页 > news >正文

P1020 [NOIP 1999 提高组] 导弹拦截

P1020 [NOIP 1999 提高组] 导弹拦截 - 洛谷

P1020 [NOIP 1999 提高组] 导弹拦截 - 洛谷

题解来自洛谷题解,仅仅用于自己整理知识

这段代码是 NOIP1999 提高组第一题「导弹拦截系统」的一个 高效 O(n log n) 解法,目标是解决两件事:

  • 最多能拦截多少导弹(只有一套系统)
    → 即求一个 最长不升子序列(Longest Decreasing Subsequence,LDS) 的长度

  • 拦截所有导弹最少需要几套系统
    → 即将整个序列划分成最少数量的 不升子序列

✅ 解题思路概览

这段代码用了经典的 贪心 + 二分 + tail 数组维护方式(也是 LIS 的优化思路,反过来处理即可用于 LDS)。

const int N = 1e7 + 10;
int n, res, a[N], f[N];
  • a[N]:存储导弹高度

  • f[N]:辅助数组,类似于“每种长度的序列的末尾最小值”

  • n:导弹总数

  • res:结果值(最长长度)

读入输入+数据反转
while(cin >> x) a[++n] = x;
reverse(a + 1, a + n + 1);

为什么要反转 a[1...n]

因为原题求的是 最长不升子序列(LDS)
而 LIS(最长上升子序列)的经典做法就是用 lower_bound 来查找位置。

把问题反转之后求 LIS,就等价于在原序列上求 LDS。

第一问:最长不升子序列(LDS)长度

memset(f, 0x3f, sizeof(f)); // 初始化 f[] 为无穷大
for(int i = 1; i <= n; i++) {int l = 1, r = i;while(l < r) {int mid = (r + l) / 2;if(f[mid] > a[i]) r = mid;else l = mid + 1;}f[l] = min(f[l], a[i]);res = max(res, l);
}
cout << res << endl;

✅ 说明:

我们想维护一个数组 f[i]

  • 表示长度为 i 的不升子序列末尾的最小值

🚀 每次二分查找:

找的是 f[pos] > a[i] 的最小 pos,因为反转后问题就成了找 最长上升子序列

  • 如果找到,就替换 f[pos] 为更小的值,有利于后续增长

  • 如果找不到,就在末尾新增

🔍 解释(二分查找目标):

寻找最小的下标 l,使得 f[l] > a[i]

换句话说:

  • 找到一个位置 l,可以插入 a[i],以维持 f[1...l] 是严格递减的

  • 这是反转过的最长上升子序列的技巧 —— 用 lower_bound 思路求 LDS

✅ 为什么这样做?

我们维护 f[] 的单调性,使得:

  • f[i] 越小越好 → 更容易接后面的更小值

  • 如果 a[i] 能接在某个 f[l] 之后,就更新它(使结尾更优)

f[l] = min(f[l], a[i]);

🔍 解释:

a[i] 放入 f[l] 这个位置(更新为较小值):

  • 表示存在一个长度为 l 的不升子序列,其结尾为 a[i]

  • 如果原来的 f[l] 更大,那现在用更小的 a[i] 替代它,有利于后续元素加入

 第二问:最少系统数(最少不升子序列划分)

memset(f, 0x3f, sizeof(f));
reverse(a + 1, a + n + 1); // 再反回来
res = 0;
for (int i = 1; i <= n; i++) {int l = 1, r = i;while (l < r) {int mid = (l + r) / 2;if (f[mid] >= a[i]) r = mid;else l = mid + 1;}f[l] = min(f[l], a[i]);res = max(res, l);
}
cout << res;
问题方法目标二分条件更新策略
最长不升子序列LIS on reversed找最长f[mid] > a[i]f[l] = min(f[l], a[i])
最少系统数量贪心组系统分组f[mid] >= a[i]f[l] = min(f[l], a[i])
http://www.lryc.cn/news/603663.html

相关文章:

  • 动态库示例
  • 代码随想录算法训练营第三十五天
  • BGP团体属性
  • MybatisPlus-20.插件功能-通用分页实体与MP转换
  • 【IQA技术专题】纹理相似度图像评价指标DISTS
  • AAA 与 FTP:网络认证授权及文件传输的原理与实践
  • 如何在 Ubuntu 24.04 或 22.04 Linux 上安装和运行 Redis 服务器
  • Redis的持久化策略-AOF和RDB(详细图解)
  • 广告投放数据与管理全解析:从数据解读到高效运营
  • ansible 使用更高版本的python版本
  • 设计一个高可用、可拓展、监控报警系统,使用普罗米修斯和grafana,并给出go实现
  • 第2章 cmd命令基础:常用基础命令(1)
  • SQL排查、分析海量数据以及锁机制
  • 微算法科技(NASDAQ:MLGO)应用区块链联邦学习(BlockFL)架构,实现数据的安全传输
  • Java:为什么需要通配符捕获(wildcard capture)
  • 大文件的切片上传和断点续传前后端(Vue+node.js)具体实现
  • 巡台效率:精准胜勤快
  • 基于YOLOP与GAN的图像修复与防御系统设计与实现
  • 把查出来的值加上双引号,并逗号分隔
  • 宇树 G1 部署(九)——遥操作控制脚本 teleop_hand_and_arm.py 分析与测试部署
  • 汇总数据(使用聚集函数)
  • 智能制造的空间度量:机器视觉标定技术解析
  • 微店商品详情接口micro.item_get请求参数响应参数解析
  • 以太坊十年:智能合约与去中心化的崛起
  • Linux文件归档和备份
  • 自动调优 vLLM 服务器参数(实战指南)
  • IDEA中全局搜索快捷键Ctrl+Shift+F为何失灵?探寻原因与修复指南
  • ARM7微处理器的核心优势
  • 如何在Windows操作系统上通过conda 安装 MDAnalysis
  • 继续打卡day6