[NOIP1999 提高组] 导弹拦截
题目描述
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度,计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入格式
一行,若干个整数,中间由空格隔开。
输出格式
两行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
样例 #1
样例输入 #1
389 207 155 300 299 170 158 65
样例输出 #1
6
2
提示
对于前
50
%
50\%
50% 数据(NOIP 原题数据),满足导弹的个数不超过
1
0
4
10^4
104 个。该部分数据总分共
100
100
100 分。可使用
O
(
n
2
)
\mathcal O(n^2)
O(n2) 做法通过。
对于后
50
%
50\%
50% 的数据,满足导弹的个数不超过
1
0
5
10^5
105 个。该部分数据总分也为
100
100
100 分。请使用
O
(
n
log
n
)
\mathcal O(n\log n)
O(nlogn) 做法通过。
对于全部数据,满足导弹的高度为正整数,且不超过 5 × 1 0 4 5\times 10^4 5×104。
此外本题开启 spj,每点两问,按问给分。
NOIP1999 提高组 第一题
解题思路
读了一遍题目,意思就是让我们用
O
(
n
log
n
)
\mathcal O(n\log n)
O(nlogn)的算法通过此题.
题意是让我们求最长不升子序列,但是LIS算法只能通过
O
(
n
2
)
\mathcal O(n^2)
O(n2) 的题.
所以我们要考虑二分或贪心,但是LIS算法本身就是为了避免贪心的存在.
所以只能考虑二分.
我们发现可以用二分替代一层循环,可将复杂度降至
O
(
n
log
n
)
\mathcal O(n\log n)
O(nlogn).
AC代码
#include<bits/stdc++.h>
using namespace std;
int a[100100],n,b[100100],ans,ans1;
int main(){
while(cin>>a[++n]);
b[0]=2e9+10;
for(int i=1;i<=n;i++){
if(a[i]<=b[ans])b[++ans]=a[i];
else{
int l=1,r=ans;
while(l<r){//二分
int mid=l+r>>1;
if(b[mid]<a[i])r=mid;
else l=mid+1;
}
b[l]=a[i];
}
}
cout<<ans-1<<endl;
b[0]=-2e9-10;
for(int i=1;i<=n;i++){
if(a[i]>b[ans1])b[++ans1]=a[i];
else{
int l=1,r=ans1;
while(l<r){//二分
int mid=l+r>>1;
if(b[mid]>=a[i])r=mid;
else l=mid+1;
}
b[l]=a[i];
}
}
cout<<ans1;
return 0;
}