洛谷 P1020 [NOIP1999 普及组] 导弹拦截【一题掌握三种方法:动态规划+贪心+二分】最长上升子序列LIS解法详解

news2024/11/26 14:59:14

P1020 [NOIP1999 普及组] 导弹拦截

  • 前言
  • 题目
    • 题目描述
    • 输入格式
    • 输出格式
    • 样例 #1
      • 样例输入 #1
      • 样例输出 #1
    • 提示
    • 题目分析
    • 注意事项
  • 代码
    • 动态规划(NOIP要求:时间复杂度O(n^2^))
    • 贪心+二分(O(nlgn))
  • 后话
    • 额外测试用例
      • 样例输入 #1
      • 样例输出 #1
      • 样例输入 #2
      • 样例输出 #2
    • 王婆卖瓜
  • 参考来源

前言

再做几题动态规划我们就去做图搜索,另外最近要期中考因为还是需要绩点的,所以断更几天。期中考后应该就开始图搜索算法啦!
隐约记得这题当作期末或者期中考的题目,应该是算法的,至少当时我是没有做出来的,现在我凭自己的实力做出来了O(n2),虽然没有很快做出来卡了好久,但是至少进步是很明显的!然后又学习了一下贪心的思想也是做出来O(lgn)!希望跟着我刷题的宝子们跟着我的进度也能有大的进步!

题目

题目描述

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

输入导弹依次飞来的高度,计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

输入格式

一行,若干个整数,中间由空格隔开。

输出格式

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

样例 #1

样例输入 #1

389 207 155 300 299 170 158 65

样例输出 #1

6
2

提示

对于前 50 % 50\% 50% 数据(NOIP 原题数据),满足导弹的个数不超过 1 0 4 10^4 104 个。该部分数据总分共 100 100 100 分。可使用 O ( n 2 ) \mathcal O(n^2) O(n2) 做法通过。
对于后 50 % 50\% 50% 的数据,满足导弹的个数不超过 1 0 5 10^5 105 个。该部分数据总分也为 100 100 100 分。请使用 O ( n log ⁡ n ) \mathcal O(n\log n) O(nlogn) 做法通过。

对于全部数据,满足导弹的高度为正整数,且不超过 5 × 1 0 4 5\times 10^4 5×104

此外本题开启 spj,每点两问,按问给分。


upd 2022.8.24 \text{upd 2022.8.24} upd 2022.8.24:新增加一组 Hack 数据。

题目分析

  抛开第二问,我们先来关于第一问,也就是第一行的输出。
  题目第一问很明显是一个最长非递增子序列的计算或者说最长非严格递减子串。我给出了两个方法,一个是动态规划,但是由于我的技术不精或者说确实没办法,只能达到O(n2)。另一种是贪心+二分,就可以达到O(nlgn)。
  首先介绍一下动态规划方法,与我前面的挖地雷类似,首先找到数值变化的点在哪:显然是找到一个更小的值可以加到这个非递增子序列上。但是我们需要找到最好的值,所以我们建立一个f数组,用来存储当前节点的最好结果,然后我们遇到下一个点的时候就可以更新包括这个节点的最好结果,如此下去直到最后一个节点,然后遍历整个f数组,找到最好的值输出。具体代码见下方,但是不足是时间复杂度不太行
  接着我们思考贪心的算法,贪心好像需要满足一个前提条件局部最优解是全局最优解的一部分,我这里就不证明了(我也不太会)。直接来看贪心的思想。对于每个数,既可以把它接到已有的导弹拦截后面,也可以建立一个新系统。要使子序列数最少,应尽量不建立新序列。另外,应让每个导弹系统的末尾尽可能大,这样能接的数更多。因为一个数若能接到小数后面,必然能接到大数后面,反之则不成立。我们维护一个栈,用来表示最长非递增子序列,根据贪心算法的思想这个栈的维护需要做到以下两点:1.比栈顶小的数直接入栈;2.找到栈里最小的大于该数的元素,将这个元素替换成这个数。又因为这个栈是从大到小排序,所以我们找位置的时候可以使用二分查找来节省时间。代码也是看下方。
  接着就是解决第二问的问题,首先需要引入一个Dilworth定理:

Dilworth定理:对于任意有限偏序集,其最大反链中元素的数目必等于最小链划分中链的数目。

  换句话讲,最长上升子序列的长度就是能构成的不上升序列的个数。于是系统求个数其实就是求最长递增子序列或者说LIS的长度,然后按照上面的方法修改一下大于和小于等于号就可以了!是不是很奇妙,所以这题还是很有难度的,但凡你不知道这个定理,想要做出来不是一件容易的事情。

注意事项

1.输入没有给定长度的处理办法
C++

int x,n=-1;
while(cin>>x)a[++n]=x;++n;//从0开始,n表示个数

int x,n=0;
while(cin>>x)a[++n]=x;//从1开始,n表示个数

//不知道为什么while(cin>>a[n++]);不行

C语言

while(~scanf("%d",&a[++n])); --n;
while (scanf("%d", a+(++n)) != EOF) ; --n;

python(待补充)

#有没有帅哥美女知道的评论区告诉我一下

2.注意是最长非严格递减数列,所以是可以包括等于的情况,判断时应该是a[j]>=a[i]

3.二分法while里面记得判断条件是a[i]>f[mid],有个笨蛋写成a[i]>f[point]了。

代码

动态规划(NOIP要求:时间复杂度O(n2))

NOIP的要求是O(n2),所以我们可以使用动态规划过前十个点的数据
哭了

#include<iostream>
using namespace std;
int a[100007]= {0},path[27]= {0},f1[100007]= {0},f2[100007]= {0};
int main()
{
	int n=-1,maxx=0,minn=0,flag1=0,flag2=0,x;
	while(cin>>x)a[++n]=x;++n;
	f1[0]=1;
	f2[0]=1;
	for(int i=1; i<n; i++) {
		maxx=0;
		minn=0;//每次都要重新初始化
		for(int j=0; j<i; j++) {
			if(f1[j]>maxx&&a[i]<=a[j]) {//找到符合条件的最大值
				maxx=f1[j];
			}
			if(f2[j]>minn&&a[i]>a[j]) {
				minn=f2[j];
			}
		}
			f1[i]=maxx+1;
			f2[i]=minn+1;
	}
	int ans1=0,ans2=0;
	for(int i=0; i<n; i++) {
		if(f1[i]>ans1)
			ans1=f1[i];
		if(f2[i]>ans2)
			ans2=f2[i];
	}
	cout<<ans1<<endl<<ans2;
	return 0;
}

贪心+二分(O(nlgn))

本法巧妙利用了贪心的性质,并且用二分法来查找最大值,将时间复杂度打到O(nlgn)。
并且有个偷懒的地方是使用了一个判断函数,将两个计算子串长度的函数合并成一个!
栈还保存了最长上升或递减子序列的列表
拿下!
噔噔噔!代码闪亮登场!

#include<iostream>
using namespace std;

int a[100007]= {0},f[100007]= {0};
void test(int f[],int x){//没有用就是用来测试的 
	for(int i= 1; i<=x;i++){
		cout<<f[i]<<" ";
	}
	cout<<endl;
}
bool relation(int x,int y,int rela)//用来返回判断值的 
{
	if(rela==1) {
		return x>y;
	} else
		return x<=y;
}
int Lg_sequence(int n,int rela)//计算相反的两个最长子串 
{
	int f[100007]= {0};
	int point=1;
	f[1]=a[0];
	for(int i = 1 ; i < n ; i ++) {
		if(relation(a[i],f[point],rela)) {//符合子串直接入栈 
			f[++point]=a[i];
		} else {
			int l = 1, r = point;
            while (l < r) {//找到大于该值的最小的栈值 
                int mid = (l + r) >> 1;
                if (relation(a[i],f[mid],!rela)) {
                    r = mid;
                } else {
                    l = mid + 1;
                }
            }
            f[l] = a[i];
		}
	}
	return point;
}
int main()
{
	int n=-1,maxx=0,minn=0,point=1,x;
	while(cin>>x)a[++n]=x;++n;//n表示数组长度 
	cout<<Lg_sequence(n,0)<<endl<<Lg_sequence(n,1);
	return 0;
}

后话

额外测试用例

因为太笨获得了两个测试用例

样例输入 #1

330 309 267 287 315 380 365 363 364 351 316 381 355 372 289 284 356 299 369 361 327 372 360 282 327 280 258 293 258 254 298 320 324 314 273 340 251 324 327 339 270 248 275 318 321 283 293 341 247 321 318 270 328 322 294 299 259 304 302 286 287 239 333 300 269 240 269 275 296 292 254 308 325 285 218 282 221 288 238 307 212 263 316 300 264 278 215 304 306 296 218 206 225 206 266 250 288 208 241 297 264 211 285 294 236 206 292 215 249 195 206 202 198 276 258 199 192 207 195 261 253 212 206 214 269 234 254 250 196 246 244 227 229 238 194 221 192 243 181 233 180 242 206 247 223 195 187 210 181 176 214 201 209 207 231 222 199 217 212 222 197 168 217 195 193 216 163 203 163 230 206 201 153 184 177 193 174 189 175 155 148 197 184 201 169 155 182 166 156 202 204 193 143 199 167 194 174 195 181 171 163 170 173 169 184 160 130 132 166 128 160 149 140 182 144 127 140 175 134 175 146 169 159 176 152 118 131 120 156 119 141 144 121 146 116 160 136 116 123 135 109 158 127 115 127 148 116 126 140 109 129 122 123 120 109 114 134 98 95 133 108 108 124 115 99 92 97 132 106 116 115 120 116 123 91 94 107 115 114 110 98 81 94 109 114 86 92 97 105 107 94 98 79 93 83 96 70 71 88 71

样例输出 #1

69
11

样例输入 #2

90 103 99 83 102 70 86 70 99 71

样例输出 #2

5
3

王婆卖瓜

感觉有收获或者想跟上我的进度刷题的,可以点个关注,或者点赞收藏评论都可以!

参考来源

NOIP 1999 普及组
洛谷题目-传送门
参考材料-TernaryTree

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1186320.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构:Map和Set(2):相关OJ题目

目录 136. 只出现一次的数字 - 力扣&#xff08;LeetCode&#xff09; 771. 宝石与石头 - 力扣&#xff08;LeetCode&#xff09; 旧键盘 (20)__牛客网 (nowcoder.com) 138. 随机链表的复制 - 力扣&#xff08;LeetCode&#xff09; 692. 前K个高频单词 - 力扣&#xff08…

“百人专家团”背书 袋鼠妈妈“双十一”蓄势待发

从万千商家的角度来看,“双十一”实际上就是一场没有硝烟的“战争”,只有用心做产品的品牌才能成为常胜将军,要想在双十一脱颖而出在同品类榜单上占据有利位置,品牌力和产品力二者缺一不可。而专注母婴护肤10年的袋鼠妈妈品牌便是如此,从品牌诞生以来,始终专注母婴用户需求,打造…

STM32MPU6050角度的读取(STM32驱动MPU6050)

注&#xff1a;文末附STM32驱动MPU6050代码工程链接&#xff0c;需要的读者请自取。 一、MPU6050介绍 MPU6050是一款集成了三轴陀螺仪和三轴加速度计的传感器芯片&#xff0c;由英国飞利浦半导体&#xff08;现为恩智浦半导体&#xff09;公司生产。它通过电子接口&#xff08…

面包屑实现

背景&#xff1a;面包屑根据菜单内容显示不同内容。首页永远存在&#xff0c;后面的活动管理及多级菜单的面包屑展示。 实现原理&#xff1a; 通过this.$route.matched获取所有匹配路由&#xff0c;将处理首页外的其他路由设置到一个数组中&#xff0c;再通过数组循环方式显示…

Linux/centos上如何配置管理Web服务器?

Linux/centos上如何配置管理Web服务器&#xff1f; 1 Web简单了解2 关于Apache3 如何安装Apache服务器&#xff1f;3.1 Apache服务安装3.2 httpd服务的基本操作 4 如何配置Apache服务器&#xff1f;4.1 关于httpd.conf配置4.2 常用指令 5 简单实例 1 Web简单了解 Web服务器称为…

一篇文章让你Docker从入门到精通

一篇文章让你Docker从入门到精通 Docker简介docker的3要素docker安装--centos7示例docker底层原理docker常用命令docker镜像原理数据共享--容器数据卷数据卷容器dockerfile解析Dockerfile实战一 使用dockerfile构建ubuntu镜像&#xff0c;并在里面安装vim及网络工具 一张图展示…

2023 年微服务后端开发的 11 个最佳工具

前言 微服务架构以将复杂的应用程序分解为易管理的服务而闻名&#xff0c;然而&#xff0c;管理微服务是一项具有挑战性的任务。为了确保开发工作流程的高效性&#xff0c;需要采用特定的工具。 在本文中&#xff0c;小编将为您介绍2023年最热的11款后端微服务开发工具&#…

什么是CE认证?蓝牙耳机出口欧盟CE认证如何办理?CE-RED认证办理

蓝牙耳机是一种基于蓝牙技术的一种小型设备&#xff0c;只需要把这种轻巧的设备藏在耳机边而不需要直接使用通讯设备&#xff08;手机、电脑等&#xff09;就可以实现自由通话。蓝牙耳机就是将蓝牙技术应用在免持耳机上&#xff0c;让使用者可以免除恼人电线的牵绊&#xff0c;…

软件测试/测试开发丨接口自动化测试学习笔记,整体结构响应断言

点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接&#xff1a;https://ceshiren.com/t/topic/27982 一、结构断言介绍 针对于“大响应数据”如何断言 针对主要且少量的业务断言其他字段不做数据正确性断言&#xff0c;只做类型与整体结构校验与前面…

【Ruoyi管理后台】用户登录强制修改密码

近期有个需求&#xff0c;就是需要调整Ruoyi管理后台&#xff1a;用户如果三个月(长时间)未修改过密码&#xff0c;需要在登录时强制修改密码&#xff0c;否则不能登录系统。 一、后端项目调整 从需求来看&#xff0c;我们需要在用户表增加一个字段&#xff0c;用于标记用户最…

转换流详解

问题引出&#xff1a;不同编码读取乱码问题 1、之前我们使用字符流读取中文是否有乱码&#xff1f; 没有的&#xff0c;因为创建字符流时如果不指定编码&#xff0c;那么使用的编码是jvm的默认编码&#xff0c;和文件编码都是UTF-8。 Creates a new FileReader, given the n…

MybatisPlus之新增操作并返回主键ID

在应用mybatisplus持久层框架的项目中&#xff0c;经常遇到执行新增操作后需要获取主键ID的场景&#xff0c;下面将分析及测试过程记录分享出来。 1、MybatisPlus新增方法 持久层新增方法源码如下&#xff1a; public interface BaseMapper<T> extends Mapper<T> …

RxJava/RxAndroid的操作符使用(二)

文章目录 一、创建操作1、基本创建2、快速创建2.1 empty2.2 never2.3 error2.4 from2.5 just 3、定时与延时创建操作3.1 defer3.2 timer3.3 interval3.4 intervalRange3.5 range3.6 repeat 二、过滤操作1、skip/skipLast2、debounce3、distinct——去重4、elementAt——获取指定…

xshell是什么软件,1000字让你完全了解xshell

很多从事开发或网络安全的人都或多或少知道xshell是什么软件&#xff0c;但是如果没有试用过的话可能对它的功能并不完全了解。今天小编就带你详细了解一下Xshell究竟是什么。 xshell是什么软件 一、xshell是什么软件 Xshell是一款功能强大的SSH&#xff08;Secure Shell&…

Jdk 1.8 for mac 详细安装教程(含版本切换)

Jdk 1.8 for mac 详细安装教程&#xff08;含版本切换&#xff09; 官网下载链接 https://www.oracle.com/cn/java/technologies/downloads/#java8-mac 一、选择我们需要安装的jdk版本&#xff0c;这里以jdk8为例&#xff0c;下载 macOS 版本&#xff0c;M芯片下载ARM64版本…

基于驾驶训练算法的无人机航迹规划-附代码

基于驾驶训练算法的无人机航迹规划 文章目录 基于驾驶训练算法的无人机航迹规划1.驾驶训练搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用驾驶训练算法来优化无人机航迹规划。 …

07 # 手写 find 方法

find 的使用 find() 方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。 ele&#xff1a;表示数组中的每一个元素index&#xff1a;表示数据中元素的索引array&#xff1a;表示数组 <script>var arr [1, 3, 5, 7, 9];var result arr.find(fun…

SpringBoot加载测试类属性和配置说明

一、项目准备 1.创建项目 2.配置yml文件 test:name: FOREVERlove: sing二、测试类属性 1.Value 说明&#xff1a;读取yml中的数据。 package com.forever;import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Value; import org.spr…

用中文编程工具编写的代码实现如图所示效果,请分享一下用你所学的编程语言写下这个代码,大家一起交流学习

用中文编程工具编写的代码实现如图所示效果&#xff0c;请分享一下用你所学的编程语言写下这个代码&#xff0c;大家一起交流学习 编程要求如图&#xff1a;在输入框里输入行数&#xff0c;随便输入多少&#xff0c;点击按钮&#xff0c;即刻显示如图所示效果&#xff0c;下一…

nacos注册中心/配置中心的使用

Nacos下载: https://github.com/alibaba/nacos/releases Nacos启动&#xff1a; 此处为了演示方便&#xff0c;下载的是 Windows版本 nacos-server-2.2.2.zip 。 进入 nacos-server-2.2.2\nacos\bin 文件夹&#xff0c;按shift和右键&#xff0c;选择"在此处打开PowerS…