题目描述
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度(雷达给出的高度数据是\le 50000≤50000的正整数),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入格式
11行,若干个整数(个数\le 100000≤100000)
输出格式
22行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入
389 207 155 300 299 170 158 65
输出
6
2
/*
* “以后每一发炮弹都不能高于前一发的高度”说明这是一个最长不上升子序列问题
*
* “拦截所有导弹需要配备多少套这样的系统”是一个最长上升子序列问题,
* 可以这样来联想:dp2[]数组的下标代表了系统的编号(从1开始),对
* dp2[]数组的元素覆盖(在数组中寻找第一个大于新导弹高度的元素然后覆盖)
* 的意义是从该编号的系统来打该新导弹,然后该编号的系统能打击的高度就
* 只能是新导弹的高度了。在数组中增加元素(len2++),是因为新导弹的
* 高度大于目前所有系统能打击的最大高度,所以必须配备新系统。
*
* 在覆盖时其实是一种贪心的思想,新导弹必须有系统来打,选择目前能打的且打击
* 高度值最小的系统来打,留着打击高度值较大的系统来打击未知的高度值可能更大的
* 导弹,保证每次都取最优
*
*/
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 100005;
int a[maxn]; //导弹的高度值
//最长不上升子序列
int len1; //序列长度
int dp1[maxn]; //dp1[i]表示长度为i的序列的末尾元素
//最长上升子序列
int len2; //序列长度
int dp2[maxn]; //dp2[i]表示长度为i的序列的末尾元素
int main(void)
{
//输入导弹的高度值
int x;
int n = 0;
while (cin >> x)
{
a[++n] = x;
}
//初始化
dp1[1] = dp2[1] = a[1];
len1 = len2 = 1;
int ptr;
for (int i = 2; i <= n; i++)
{
//最长不上升子序列
if (a[i] <= dp1[len1])
{
dp1[++len1] = a[i];
}
else
{
//等于是可以继续接在后面的,寻找一个小于的位置
ptr = upper_bound(dp1 + 1, dp1 + 1 + len1, a[i], greater<int>()) - dp1;
dp1[ptr] = a[i];
}
//最长上升子序列
if (a[i] > dp2[len2])
{
dp2[++len2] = a[i];
}
else
{
//寻找第一个大于等于的元素的位置
ptr = lower_bound(dp2 + 1, dp2 + 1 + len2, a[i]) - dp2;
dp2[ptr] = a[i];
}
}
cout << len1 << endl << len2;
}