某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。
但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。
某天,雷达捕捉到敌国的导弹来袭。
由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数,导弹数不超过1000),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入格式
共一行,输入导弹依次飞来的高度。
输出格式
第一行包含一个整数,表示最多能拦截的导弹数。
第二行包含一个整数,表示要拦截所有导弹最少要配备的系统数。
数据范围
雷达给出的高度数据是不大于 30000 的正整数,导弹数不超过 1000。
输入样例:
389 207 155 300 299 170 158 65
输出样例:
6
2
难度:简单 |
时/空限制:1s / 64MB |
总通过数:16814 |
总尝试数:31014 |
来源:《信息学奥赛一本通》 , NOIP1999 , HDU1257, kuangbin专题 |
算法标签dp |
题解:
从前往后做一遍最长下降子序列,同时维护一个数组长度为cnt的单调不减数组q[N]数组 q[N] 中每个元素维护的是当前以 q[i] 结尾的下降子序列
于是,对于第 i 个元素来说,他能插入的到 q[N] 中的哪个下降子序列中,是存在一个二分性质的
由于要求的是下降子序列且 q[N] 是单调不减的
因此对于所有的 w[i] ,必然存在一个边界 j ,满足∀k∈[0,j),有q[k]<w[i]且 ∀k∈[j,cnt],有w[i]≤q[k]于是我们就可以用二分来优化找满足性质:w[i]≥q[k] 的区间左端点即可
具体代码如下:
#include <sstream>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1010;
int n;
int h[N], f[N], q[N];
int main()
{
string line;
getline(cin, line);
stringstream ssin(line);
while (ssin >> h[n]) n ++ ;
int res = 0, cnt = 0;
for (int i = 0; i < n; i ++ )
{
f[i] = 1;
for (int j = 0; j < i; j ++ )
if (h[i] <= h[j])
f[i] = max(f[i], f[j] + 1);
res = max(res, f[i]);
int k = 0;
while (k < cnt && q[k] < h[i]) k ++ ;
if (k == cnt) q[cnt ++ ] = h[i];
else q[k] = h[i];
}
printf("%d\n", res);
printf("%d\n", cnt);
return 0;
}