DP - LIS - 拦截导弹 - NOIP1999
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。
但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。
某天,雷达捕捉到敌国的导弹来袭。
由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数,导弹数不超过1000),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入格式
共一行,输入导弹依次飞来的高度。
输出格式
第一行包含一个整数,表示最多能拦截的导弹数。
第二行包含一个整数,表示要拦截所有导弹最少要配备的系统数。
输入样例:
389 207 155 300 299 170 158 65
输出样例:
6
2
分析:
给 定 一 个 序 列 , 要 求 两 个 问 题 : ① 、 最 长 非 递 增 子 序 列 的 长 度 。 ② 、 原 序 列 最 少 能 够 分 成 几 个 最 长 非 递 增 子 序 列 。 给定一个序列,要求两个问题:\\①、最长非递增子序列的长度。\\②、原序列最少能够分成几个最长非递增子序列。 给定一个序列,要求两个问题:①、最长非递增子序列的长度。②、原序列最少能够分成几个最长非递增子序列。
要 覆 盖 掉 整 个 原 序 列 , 那 么 每 个 数 都 要 被 覆 盖 掉 因 此 , 可 以 从 贪 心 的 角 度 思 考 , 每 次 去 除 的 非 递 增 子 序 列 一 定 要 尽 量 的 长 , 去 除 的 次 数 就 是 最 终 答 案 。 即 对 每 个 元 素 而 言 , 要 让 该 元 素 后 面 能 够 接 的 元 素 尽 量 的 多 。 要覆盖掉整个原序列,那么每个数都要被覆盖掉\\因此,可以从贪心的角度思考,每次去除的非递增子序列一定要尽量的长,去除的次数就是最终答案。\\即对每个元素而言,要让该元素后面能够接的元素尽量的多。 要覆盖掉整个原序列,那么每个数都要被覆盖掉因此,可以从贪心的角度思考,每次去除的非递增子序列一定要尽量的长,去除的次数就是最终答案。即对每个元素而言,要让该元素后面能够接的元素尽量的多。
这 个 思 想 与 单 调 队 列 优 化 最 长 上 升 子 序 列 是 一 致 的 。 这个思想与单调队列优化最长上升子序列是一致的。 这个思想与单调队列优化最长上升子序列是一致的。
有 结 论 : 最 长 上 升 子 序 列 的 方 案 数 = 序 列 能 够 分 成 的 最 长 非 递 增 子 序 列 的 个 数 。 有结论:最长上升子序列的方案数=序列能够分成的最长非递增子序列的个数。 有结论:最长上升子序列的方案数=序列能够分成的最长非递增子序列的个数。
具体落实:
求 方 案 数 : 对 每 个 元 素 a i , 数 组 g [ k ] : 前 i − 1 个 元 素 已 经 构 成 的 第 k 个 非 递 增 子 序 列 的 末 尾 元 素 。 对 于 a i , 我 们 遍 历 数 组 g , 找 到 第 一 个 末 尾 元 素 大 于 a i 的 元 素 g [ k ] , 将 a i 接 在 其 后 , 那 么 此 时 g [ k ] 更 新 为 a i , 也 就 是 说 第 k 个 非 递 增 子 序 列 的 末 尾 元 素 变 成 了 a i 。 求方案数:\\对每个元素a_i,数组g[k]:前i-1个元素已经构成的第k个非递增子序列的末尾元素。\\对于a_i,我们遍历数组g,找到第一个末尾元素大于a_i的元素g[k],将a_i接在其后,那么此时g[k]更新为a_i,\\也就是说第k个非递增子序列的末尾元素变成了a_i。 求方案数:对每个元素ai,数组g[k]:前i−1个元素已经构成的第k个非递增子序列的末尾元素。对于ai,我们遍历数组g,找到第一个末尾元素大于ai的元素g[k],将ai接在其后,那么此时g[k]更新为ai,也就是说第k个非递增子序列的末尾元素变成了ai。
最 后 非 递 增 子 序 列 的 个 数 就 是 最 终 的 方 案 数 。 最后非递增子序列的个数就是最终的方案数。 最后非递增子序列的个数就是最终的方案数。
拿
样
例
举
例
:
拿样例举例:
拿样例举例:
i
=
1
:
g
[
0
]
=
389
i=1:g[0]=389
i=1:g[0]=389
i
=
2
:
g
[
0
]
=
207
i=2:g[0]=207
i=2:g[0]=207
i
=
3
:
g
[
0
]
=
155
i=3:g[0]=155
i=3:g[0]=155
i
=
4
:
g
[
0
]
=
155
,
g
[
1
]
=
300
i=4:g[0]=155,g[1]=300
i=4:g[0]=155,g[1]=300
i
=
5
:
g
[
0
]
=
155
,
g
[
1
]
=
299
i=5:g[0]=155,g[1]=299
i=5:g[0]=155,g[1]=299
i
=
6
:
g
[
0
]
=
155
,
g
[
1
]
=
170
i=6:g[0]=155,g[1]=170
i=6:g[0]=155,g[1]=170
i
=
7
:
g
[
0
]
=
155
,
g
[
1
]
=
158
i=7:g[0]=155,g[1]=158
i=7:g[0]=155,g[1]=158
i
=
8
:
g
[
0
]
=
65
,
g
[
1
]
=
158
i=8:g[0]=65,g[1]=158
i=8:g[0]=65,g[1]=158
代码:
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1010;
int n,a[N],f[N],g[N];
int main()
{
while(cin>>a[++n]);
int res=0;
for(int i=1;i<n;i++)
{
f[i]=1;
for(int j=1;j<i;j++)
if(a[i]<=a[j])
f[i]=max(f[i],f[j]+1);
res=max(res,f[i]);
}
cout<<res<<endl;
int cnt=0;
for(int i=1;i<n;i++)
{
int k=0;
while(k<cnt&&g[k]<a[i]) k++;
g[k]=a[i];
if(k>=cnt) cnt++;
}
cout<<cnt<<endl;
return 0;
}