【题解】P1020 导弹拦截
【题解】P1020 导弹拦截
从n^2到nlogn
第二问就是贪心,不多说
第一问:
简化题意:求最长不下降子序列
普通n^2:
for (int i = 1; i <= n; i++)
for (int j = 1; j < i; j++)
if(a[j] >= a[i])
f[i] = max(f[i], f[j] + 1);
cout << f[n];
另一种n^2级,可能快一点点(还没交,不知对不对)
f[0] = 1;
for (int i = 1; i <= n; i++)
{
if(a[i] == 0)
continue;
f[a[i]] = f[a[i] - 1] + 1;
for (int j = a[i]; j <= max_ai; j++)
f[j] = max(f[j], f[a[i]]);
}
cout << f[max_ai] << endl;
接下来就是大佬讲的nlogn
题解(@w1049344862)
首先是upper_bound() 和lower_bound()的用法
然后是神奇的栈操作
w1049344862曰:
O(nlogn)求出最长不上升子序列的长度
(即一套系统最多拦截数)
1.实现方式
首先我们需要一个数组a,存储从第1个到第n个导弹的高度
然后一个数组d(其实是个栈),存储不上升序列
把a中的每个元素挨个加到d里面:
(a中第i个元素为a[i],d长度为len,d中最后一个(也是最小的一个)为d[len])
如果a[i] <= d[len],说明a[i]可以接在d后面(而整个d还是有序的),那就简单粗暴地把a[i]丟进d:
d[ ++len ] = a[i]
如果a[i] > d[len],说明a[i]接不上
但是我们发扬瞎搞精神:接的上要接,接不上创造条件也要接!
强行把a[i]塞进去:
在d中找到第一个小于a[i]的数,把它踹了,用a[i]代替它!(为什么正确在下面)
假设这个数是y,怎样踹掉它呢?
很明显,我们需要使用lower_bound和upper_bound来查找
第一步,找一个听起来无比正确的理由,比如它占着位置不干活啦,干起活来还不如a[i]啦,naive啦,它too young啦,too simple啦......反正能骗过lower_bound和upper_bound就行
(lower_bound&&upper_bound:你当我们傻)(w1049:真聪明)
接下来,特别有正义感的lower_bound和upper_bound就会去把y给拎出来
第二步,考虑使用什么
我们知道,要求的是最大不上升子序列长度,也就是如果两个元素相等也是可以的
所以我们踹人就不用踹等于a[i]的了
结合上面,应该使用upper_bound(终于想起来它了)并且使用>作为比较器(这是个下降序列)
第三步,直接开搞
int p = upper_bound(d + 1, d + 1 + len, a[i], greater () ) - d;
d[p] = a[i];
成功把a[i]塞了进去
2.为什么正确
显然成立
如果y在末尾,由于y < a[i],所以y后面能接的不如a[i]多,y让位给a[i]可以让序列更长
如果y不在末尾,那y有生之年都不会再被用到了,直接踹了y就行,y咋样,who care?
注意到lower_bound只能在有序序列中使用,此时d还有序吗?
当然有序。(本文第一个句号)
假设y前一个y1,y后一个是y2,则
y1 > y > y2
因为y是第一个小于a[i]的,所以
y1 > a[i]
又因为
a[i] > y > y2
所以
y1 > a[i] > y2
对比下原来的式子
y1 > y > y2
a[i]可以完美代替y,至于y以后咋办,who care?
对于最长上升子序列,只需要把上面的过程通通换一下符号
可以用以下方法证明:
反之亦然同理,推论自然成立,略去过程QED,由上可知证毕(多么美妙的证明)
3.代码:
for(int i=2;i<=n;i++)
if(d[len]>=a[i])d[++len]=a[i];
else {
int p=upper_bound(d+1,d+1+len,a[i],greater())-d;
d[p]=a[i];
}
最后len就是要求的最大不上升子序列长度
但要注意的是,d中存储的并不是最大不上升子序列!
原因如下:
即得易见平凡,仿照上例显然,留作习题答案略,读者自证不难
以上是洛谷题解)哈哈,诙谐的作业确让人思考
为啥len=答案??
每加入一个,肯定是经比较满足最长不下降子序列后才扩栈的。
也就是在第i个元素时,len一旦+1,前提都是存在以a[i]结尾的且长为len的最长不下降子序列。
你想,更新栈内元素,使小的被较大的覆盖,并不改变原来元素所构成的序列的存在性。(这就是正确性)
而这次更新的操作,是为了贪心得到更优解(当然不是让栈内成为新的序列(栈内本来就不是个序列))。
下次有元素,加到大点的元素后面比加到小点的元素后面更优。为啥??
他的作用体现出来就是更新到栈顶时,栈顶元素变大了,自然就更有可能多捞一个比它小的新元素。
AC代码
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <stack>
#define N 100010
#define F(i,a,b) for(int i = a; i <= b; i++)
#define UF(i,a,b) for(int i = a; i >= b; i--)
using namespace std;
int a[N], n, len, d[N], max_ai, ans;
int high[50010];
int main()
{
while(cin >> a[++n])
max_ai = max(max_ai,a[n]);
n--;
d[++len] = a[1];
F(i,2,n){
if(a[i] <= d[len])
d[++len] = a[i];
else{
int p1=upper_bound(d+1,d+1+len,a[i],greater<int>())-d;//upper_bound() 本来是找大于a[i]的,此找小于a[i]的,利用greater
d[p1] = a[i];
}
}
// F(i,1,len) cout << d[i] << " ";
// cout << endl;
cout << len << endl;
F(i,1,n){
int t = 0;
F(j,a[i],max_ai){
if(high[j]){
high[j] --;
high[a[i]] ++;
t = 1;
break;
}
}
if(!t){
high[a[i]] ++;
ans ++;
}
}
cout << ans << endl;
return 0;
}
总结
写博客方面:
1.如果是给别人看,语言要有逻辑顺序,应该对铺垫知识先行处理。即使写给自己,这也是个好习惯。
2.短句
3.轻松诙谐
最重要还是学了upper_bound()和upper_bound()(仅仅是知道)
更重要是了解了这巧妙的思想
【题解】P1020 导弹拦截的更多相关文章
- luogu P1020 导弹拦截 x
首先上题目~ luogu P1020 导弹拦截 题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都 ...
- codevs1044 拦截导弹==洛谷 P1020 导弹拦截
P1020 导弹拦截 题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度.某天 ...
- p1020导弹拦截
传送门 P1020导弹拦截 题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度 ...
- 洛谷 P1020导弹拦截题解
洛谷链接:https://www.luogu.org/problem/P1020 题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到 ...
- 洛谷 P1020 导弹拦截(dp+最长上升子序列变形)
传送门:Problem 1020 https://www.cnblogs.com/violet-acmer/p/9852294.html 讲解此题前,先谈谈何为最长上升子序列,以及求法: 一.相关概念 ...
- codevs——T1044 拦截导弹 || 洛谷——P1020 导弹拦截
http://codevs.cn/problem/1044/ || https://www.luogu.org/problem/show?pid=1020#sub 时间限制: 1 s 空间限制: 1 ...
- P1020 导弹拦截(LIS)
题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度.某天,雷达捕捉到敌国的导弹 ...
- TYVJ P1020 导弹拦截 Label:水
题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度.某天,雷达捕捉到敌国的导弹 ...
- P1020 导弹拦截 (贪心+最长不降子序列)
题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度.某天,雷达捕捉到敌国的导弹 ...
随机推荐
- Docker系列-第五篇Docker容器数据卷
1.是什么 在生产环境中使用 Docker,往往需要对数据进行持久化,或者需要在多个容器之间进行数据共享,这必然涉及容器的数据管理操作 . 容器中的管理数据主要有两种方式 : 数据卷 ( Data V ...
- 干货!直击JVM底层 —— Java Class字节码文件解析
目录 前言 如何阅读class文件 基本概念 无符号数&表 常量池 魔数(magic number) & 版本号 常量池 访问标志 类引索&父类引索&接口引索集合 字段 ...
- 极简安装 TensorFlow 2.0 GPU
前言 之前写了几篇关于 TensorFlow 1.x GPU 版本安装的博客,但几乎没怎么学习过.之前基本在搞 Machine Learning 和 Data Mining 方面的东西,极少用到 NN ...
- rest实践1
REST 即表述性状态传递,是一种针对网络应用的设计和开发,可以降低开发的复杂性.是主流的Web服务实现方案. 表述性状态转移是一组构架约束条件和原则,满足这些约束条件和原则的应用程序和设计就是RES ...
- VueRouter爬坑第四篇-命名路由、编程式导航
VueRouter系列的文章示例编写时,项目是使用vue-cli脚手架搭建. 项目搭建的步骤和项目目录专门写了一篇文章:点击这里进行传送 后续VueRouter系列的文章的示例编写均基于该项目环境. ...
- Jaeger容器化部署
概述 Jaeger是由Uber开源的分布式追踪系统,一套完整的Jager追踪系统包括Jaeger-client.Jaeger-agent.Jaeger-collector.Database和Jaege ...
- 想玩转JAVA高并发,这些概念你必须懂!
我们在找工作时,经常在招聘信息上看到有这么一条:有构建大型互联网服务及高并发等经验,你第一时间想到的是媒体常说的双十一吗?带着问题,我们一起思考技术…. 高并发高并发 它是互联网分布式系统架构设计中必 ...
- Nginx在Centos 7中配置开机启动
1.创建脚本 # vi /etc/init.d/nginx #!/bin/bash # nginx Startup script for the Nginx HTTP Server # it is v ...
- spring cloud-config的client中/refresh的端点报错401
post访问/refresh端口报错如下 { "timestamp": 1537865395040, "status": 401, "error&qu ...
- 【WPF学习】第十三章 理解路由事件
每个.NET开发人员都熟悉“事件”的思想——当有意义的事情发生时,由对象(如WPF元素)发送的用于通知代码的消息.WPF通过事件路由(event routing)的概念增强了.NET事件模型.事件路由 ...