惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LangChain Blog
C
Check Point Blog
博客园 - Franky
V
Visual Studio Blog
云风的 BLOG
云风的 BLOG
aimingoo的专栏
aimingoo的专栏
Microsoft Security Blog
Microsoft Security Blog
V2EX - 技术
V2EX - 技术
AI
AI
Hacker News - Newest:
Hacker News - Newest: "LLM"
Jina AI
Jina AI
S
Security @ Cisco Blogs
Security Archives - TechRepublic
Security Archives - TechRepublic
H
Hacker News: Front Page
H
Hackread – Cybersecurity News, Data Breaches, AI and More
O
OpenAI News
Attack and Defense Labs
Attack and Defense Labs
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
爱范儿
爱范儿
H
Heimdal Security Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
G
Google Developers Blog
G
GRAHAM CLULEY
V
V2EX
The Register - Security
The Register - Security
人人都是产品经理
人人都是产品经理
B
Blog RSS Feed
Schneier on Security
Schneier on Security
M
MIT News - Artificial intelligence
Stack Overflow Blog
Stack Overflow Blog
Help Net Security
Help Net Security
大猫的无限游戏
大猫的无限游戏
C
CERT Recently Published Vulnerability Notes
The GitHub Blog
The GitHub Blog
V
Vulnerabilities – Threatpost
The Last Watchdog
The Last Watchdog
J
Java Code Geeks
S
Secure Thoughts
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
量子位
NISL@THU
NISL@THU
K
Kaspersky official blog
Engineering at Meta
Engineering at Meta
T
Threatpost
Recent Commits to openclaw:main
Recent Commits to openclaw:main
宝玉的分享
宝玉的分享
Security Latest
Security Latest
T
The Exploit Database - CXSecurity.com
博客园_首页
A
Arctic Wolf

博客园 - zealsoft

洛谷 P1816 忠诚题解 洛谷 P2384 最短路题解 洛谷 P2725 邮票题解 洛谷 P2722 总分题解 洛谷 P1219 八皇后题解 洛谷 P2921 在农场万圣节Trick or Treat on the Farm题解 洛谷 P1162 填涂颜色题解 洛谷 P1330 封锁阳光大学题解 洛谷 P1032 字串变换题解 洛谷 P1443 马的遍历题解 洛谷 P1280 尼克的任务题解 洛谷 P1141 01迷宫题解 VisualSVNServer无法卸载也无法安装,报告不是有效的MOF文件(0x8004401e)错误 视频捕捉的格式问题 一个VxWorks源代码网站 找个轻量级的Log库还挺难 TAU G2中的BitString和OctetString W32.Downadup.autorun病毒的清除 如何用Visual Studio 2005编译Wireshark的插件
洛谷 P1020导弹拦截题解
zealsoft · 2019-08-09 · via 博客园 - zealsoft

洛谷链接:https://www.luogu.org/problem/P1020

题目描述

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

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

输入格式

11行,若干个整数(个数\le 100000100000)

输出格式

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

输入输出样例

输入 #1

389 207 155 300 299 170 158 65

说明/提示

为了让大家更好地测试n方算法,本题开启spj,n方100分,nlogn200分

每点两问,按问给分


题解

这道题现在基本上已经是DP的入门问题了。

第一问实际是求一个最长不降子序列,而第二问是求最长上升子序列。

最容易理解的O(n2)的解法,而O(nlogn)的解法就费解一些了。关于这部分的原理写得最通俗易懂的是a342374071的文章:https://blog.csdn.net/a342374071/article/details/6694452

下面先贴上O(n2)的代码。

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <math.h>
 4 #include <algorithm>
 5 #include <string.h>
 6 
 7 using namespace std;
 8 
 9 const int MAXN = 1e5 + 10;
10 int n = 1, a[MAXN], d[MAXN], dp[MAXN];
11 
12 int main()
13 {
14     int ans1 = 0, ans2 = 0; 
15     while(scanf("%d", &a[n]) != EOF)
16     {
17         ++n; 
18     }
19     --n;
20     for(int i = 1; i <= n; i++)
21     {
22         d[i] = 1;
23         for(int j = 1; j < i; j++)
24         {
25             if(a[j] >= a[i])
26             {
27                 d[i] = max(d[i], d[j] + 1);
28             }
29         }
30         if(ans1 < d[i])
31         {
32             ans1 = d[i];
33         }
34     }
35     for(int i = 1; i <= n; i++)
36     {
37         dp[i] = 1;
38         for(int j = 1; j < i; j++)
39         {
40             if(a[j] < a[i])
41             {
42                 dp[i] = max(dp[i], dp[j] + 1);
43             }
44         }
45         if(ans2 < dp[i])
46         {
47             ans2 = dp[i];
48         }
49     }
50     cout << ans1 << endl;
51     cout << ans2 << endl;
52     return 0;
53 }

下面是O(nlogn)的代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <math.h>
 4 #include <algorithm>
 5 #include <string.h>
 6 
 7 using namespace std;
 8 
 9 const int MAXN = 1e5 + 10;
10 int n = 1, a[MAXN], d[MAXN], dp[MAXN], ans1 = 0, ans2 = 0, mid, l, r;
11 
12 int main()
13 { 
14     while(scanf("%d", &a[n]) != EOF)
15     {
16         ++n; 
17         continue;
18     }
19     --n;
20     d[1] = a[1];
21     dp[1] = a[1];
22     ans1 = ans2 = 1;
23     for(int i = 2; i <= n; i++)
24     {
25         if(a[i] <= d[ans1])
26         {
27             ans1++;
28             d[ans1] = a[i];
29         }
30         else
31         {
32             l = 1, r = ans1;
33             while(l < r)
34             {
35                 mid = (l + r) / 2;
36                 if(a[i] > d[mid])
37                 {
38                     r = mid;
39                 }
40                 else
41                 {
42                     l = mid + 1;
43                 }
44             }
45             d[l] = a[i];
46         }
47     }    
48     
49     for(int i = 2; i <= n; i++)
50     {
51         if(a[i] > dp[ans2])
52         {
53             ans2++;
54             dp[ans2] = a[i];
55         }
56         else
57         {
58             l = 1, r = ans2;
59             while(l < r)
60             {
61                 mid = (l + r) / 2;
62                 if(a[i] <= dp[mid])
63                 {
64                     r = mid;
65                 }
66                 else
67                 {
68                     l = mid + 1;
69                 }
70             } 
71             dp[l] = a[i];
72         }
73     }    
74     cout << ans1 << endl;
75     cout << ans2 << endl;
76     return 0;
77 }

这段代码中有个细节需要注意,就是当二分查找时等号应该放在if条件里,还是放在else里面。例如,在求不升子序列时,因为希望a[i]和d[mid]相等,则希望把a[i]替换d[mid]右侧的数据,这样可以使d[mid]右侧的数据尽可能大,从而使序列更长。所以程序里面的两个比较条件非常重要,如果疏忽了会导致WA。