题目描述
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度,计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入格式
一行,若干个整数,中间由空格隔开。
输出格式
两行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
思路
1.最少要配备多少套这种导弹拦截系统:
此题要求我们把数组划分成几个不上升子序列,求不上升子序列的最少个数.由偏序的相关知识我们可以证明出不上升子序列的最少个数即等于最长上升子序列的长度.
如果直接用dp,解法易想也方便,但dp的时间复杂度是O(n*n),不符合要求
那么我们再尝试在模拟的过程中寻找可优化的地方.
可以采用一个数组来存储各个已配置导弹拦截系统目前能有的最高拦截高度(由小到大存储),每次新读入的高度x若大于数组中最大的元素,则再增加一套拦截系统,否则找到数组中第一个大于等于x的元素,给它重新赋值为x(贪心法),表示对应的导弹拦截系统拦截高度降为x.遍历完数组后最长上升子序列也就构造完成
2.这套系统最多能拦截多少导弹
不难知道这一问其实就是求最长不上升子序列长度,它可以看作是求解最长上升子序列的相反过程再微改条件的结果(上升->下降->不上升),代码内容和其大体一致,稍作更改即可
代码
#include <iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int x,f[100005],i,g[100005],j,a[100005],k=1;
int main()
{
while(cin>>x) {
//求最长上升子序列
if (x > f[i]) f[++i] = x;
else *lower_bound(f+1, f + i+1, x) = x;
//求最长不上升子序列
if (x <= g[k]) g[++k] = x;
else *upper_bound(g + 1, g + k+1, x,greater<int>()) = x; //这里注意要使用greater
}
cout << k <<endl<<i;
return 0;
}