持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第17天,点击查看活动详情
NOIP1999 普及组导弹拦截 - 洛谷
题目描述
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度(雷达给出的高度数据是 ≤50000 的正整数),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入格式
1 行,若干个整数(个数 ≤100000)
NOIP 原题数据规模不超过 2000。
输出格式
2行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入 #1
389 207 155 300 299 170 158 65
输出 #1
6
2
问题解析
经典dp题,后面打的导弹的高度会小于等于前面的高度,问一次最多能打多少导弹,这就是求最长非上升子序列。至于要配套多少套导弹系统,则是看我们要多少次能拦截全部导弹,既然后面打的导弹不会比前面的高,那么当我们前面打了一个导弹,后面要是有比他高的导弹我们就打不了了,需要另一套系统去拦截,所以说配套的导弹系统数其实就是导弹高度的最长上升子序列的长度。对于这题来说我们就求一次最长不上升子序列长度和最长上升子序列即可。
AC代码
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>
#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 2e5 + 50;
int n, m;
signed main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
vector<int>v;
int x;
while (cin >> x)
{
v.push_back(x);
}
int n = v.size();
vector<int>dp(n + 2, 0);
dp[0] = 0;
int res = 0;
for (int i = 0; i < n; i++)
{
int l = 0, r = n;
while (l < r)
{
int mid = (l + r + 1) / 2;
if (v[i] <= dp[mid])l = mid;
else r = mid - 1;
}
dp[l + 1] = max(dp[l + 1], v[i]);
res = max(res, l + 1);
}
cout << res << endl;
vector<int>dp2(n + 2, 1e9);
dp2[0] = 0;
res = 0;
for (int i = 0; i < n; i++)
{
int l = 0, r = n;
while (l < r)
{
int mid = (l + r + 1) / 2;
if (dp2[mid] < v[i])l = mid;
else r = mid - 1;
}
dp2[l + 1] = min(dp2[l + 1], v[i]);
res = max(res, l + 1);
}
cout << res << endl;
return 0;
}
\