P1020 [NOIP1999 普及组] 导弹拦截
P1020 [NOIP1999 普及组] 导弹拦截题目AC代码1upper_bound 和 lower_boundAC代码2总结题目本博客给出本题截图:首先需要 说明 ,这个题目在 AcWing 中也有一模一样的题目,但是两个题目的数据范围不同:AcWing:AcWing 1010. 拦截导弹洛谷:P1020 [NOIP1999 普及组] 导弹拦截洛谷 中的数据范围更大,本题提供两个代码,第一个代
P1020 [NOIP1999 普及组] 导弹拦截
题目
本博客给出本题截图:
首先需要 说明:这个题目在 AcWing 中也有一模一样的题目,但是两个题目的数据范围不同:
AcWing:AcWing 1010. 拦截导弹
洛谷:P1020 [NOIP1999 普及组] 导弹拦截
洛谷 中的数据范围更大,本题提供两个代码,第一个代码在 AcWing 中可以 AC,但是在洛谷中有一半的数据会 TLE,第二个代码则在洛谷中也可以过掉
AC代码1
代码解释:
f数组表示的是在前 i 个导弹中的最长不上升子序列的长度,最后对所有的 f[i] 取一个最大值即可
g数组存储的是每一个防伪系统中的结尾导弹高度,对于每一个 h 数组中的元素,我们都会有两种选择,开一个新的防卫系统,或者是接到某一个系统的结尾
代码:
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 100010;
int f[N];
int g[N];
int h[N];
int n;
int main()
{
while (scanf("%d", &h[n]) != EOF) n ++;
int res = 0;
for (int i = 0; i < n; i ++ )
{
f[i] = 1;
for (int j = 0; j < i; j ++ )
if (h[j] >= h[i])
f[i] = max(f[i], f[j] + 1);
res = max(res, f[i]);
}
printf("%d\n", res);
int cnt = 0;
for (int i = 0; i < n; i ++ )
{
int k = 0;
while (k < cnt && g[k] < h[i]) k ++;
g[k] = h[i];
if (k >= cnt) cnt ++;
}
printf("%d\n", cnt);
return 0;
}
upper_bound 和 lower_bound
介绍第二个代码之前先来介绍一下lower_bound
和 upper_bound
,使用案例见博客:STL—algorithm(2)
若数组升序排列:lower_bound(begin, end, a)
返回数组[begin, end)
之间第一个大于或等于a的地址,找不到返回end
upper_bound(begin, end, a)
返回数组[begin, end)
之间第一个大于a的地址,找不到返回end
若数组降序排列:lower_bound(begin, end, a, greater<int>())
返回数组[begin, end)
之间第一个小于或等于a的地址,找不到返回end
upper_bound(begin, end, a, greater<int>())
返回数组[begin, end)
之间第一个小于a的地址,找不到返回end
注意:在使用这两个函数之前一定需要保证数组是有序的
AC代码2
代码解释:
本题中数组的作用在代码部分已经进行了标注,注意根据对于数组的定义,两个数组肯定是有序的
这个题说白了就是求一个最长不上升序列的长度 (不是子序列) 和一个最长上升序列的长度 (不是子序列)
求最长上升序列的长度:
求这个序列的长度实际上就是在求这套系统最多能拦截多少导弹:从前往后依次去看导弹的高度,只会有两种情况:
1.这个导弹的高度要小于等于f数组末尾的高度,那么我们就把这个导弹高度插入到我们的f数组的末尾
2.这个导弹的高度要大于f数组末尾的高度,那么我们就在f数组中找到第一个小于它的数,这里就需要用到upper_bound
,然后用这个导弹的高度,去替换掉我们找到的这个数
为什么要替换掉呢?我们把上述中的导弹高度称为a,要被替换掉的导弹的高度称为b,那么如果b在末尾,那么由于b < a,所以b后面能接的导弹数不如a的多,如果b在内部,那么b在有生之年内绝对不会再被用到了,所以把他替换掉也是无所谓的事情,注意在进行上述的一切操作中,我们的f数组内部都是有序的,读者可以想一下是为什么.
再次强调:我们求的是最长上升序列的长度,不是子序列!!!
最长上升序列的长度:求法和思路同上述,这里就不再进行过多的赘述
代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int f[N]; //f数组存储的是最长不上升序列(注意不是子序列)
int g[N]; //g数组存储的是最长上升序列(注意不是子序列)
int h[N];
int n;
int main()
{
while (cin >> h[++ n]);
n --;
int res = 1, cnt = 1;
f[1] = g[1] = h[1];
for (int i = 2; i <= n; i ++ )
{
if (h[i] <= f[res]) f[++ res] = h[i];
else
{
int k = upper_bound(f + 1, f + res + 1, h[i], greater<int>()) - f;
f[k] = h[i];
}
if (h[i] > g[cnt]) g[++ cnt] = h[i];
else
{
int k = lower_bound(g + 1, g + cnt + 1, h[i]) - g;
g[k] = h[i];
}
}
printf("%d\n%d\n", res, cnt);
return 0;
}
总结
才疏学浅,第一次真正运用到 lower_bound
和 upper_bound
,真香.
更多推荐
所有评论(0)