拦截导弹
Description
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。
但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。
某天,雷达捕捉到敌国的导弹来袭。
由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
Input
第一行为一个整数
N
,表示飞来的导弹个数,
第二行为
N
个整数,依次表示导弹飞来的高度,高度数据为不大于
Output
第一行,输出计算这套系统最多能拦截多少导弹
第二行,输出要拦截所有导弹最少要配备多少套这种导弹拦截系统。
Sample Input
8
389 207 155 300 299 170 158 65
Sample Output
6
2
Solution
由
Dilworth
定理可知,问题等价于求最长不下降子序列和最长上升子序列。
用
O(nlogn)
即可解决。
Code
#include <iostream>
#include <cstdio>
#define Max(x,y) ((x)>(y)?(x):(y))
using namespace std;
int n,top=0;
int high[100010];
int f1[100010];
int f2[100010];
int search1(int l,int r,int i){
int ans=0;
while(l<=r){
int mid=(l+r)>>1;
if(f1[mid]>=i){
ans=Max(ans,mid);
if(l!=mid+1)l=mid+1;
else break;
}
else{
if(r!=mid-1)r=mid-1;
else break;
}
}
return ans;
}
int search2(int l,int r,int i){
int ans=0;
while(l<=r){
int mid=(l+r)>>1;
if(f2[mid]<i){
ans=Max(ans,mid);
if(l!=mid+1)l=mid+1;
else break;
}
else{
if(r!=mid-1)r=mid-1;
else break;
}
}
return ans;
}
int main(){
freopen("missile.in","r",stdin);
freopen("missile.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&high[i]);
f1[0]=0x3f3f3f3f;
for(int i=1;i<=n;i++){
if(high[i]<=f1[top])f1[++top]=high[i];
else{
int pos=search1(1,top,high[i]);
if(f1[pos]>=high[i])f1[pos+1]=high[i];
}
}
printf("%d\n",top);
top=0;
for(int i=1;i<=n;i++){
if(high[i]>f2[top])f2[++top]=high[i];
else{
int pos=search2(1,top,high[i]);
if(f2[pos]<high[i])f2[pos+1]=high[i];
}
}
printf("%d\n",top);
return 0;
}