[NOIP 1999 提高组] 导弹拦截题解

题目描述

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。

输入导弹依次飞来的高度,计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

输入格式

一行,若干个整数,中间由空格隔开。

输出格式

两行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

输入输出样例

输入 #1复制

389 207 155 300 299 170 158 65

输出 #1复制

6
2

说明/提示

对于前 50% 数据(NOIP 原题数据),满足导弹的个数不超过 104 个。该部分数据总分共 100 分。可使用 O(n2) 做法通过。
对于后 50% 的数据,满足导弹的个数不超过 105 个。该部分数据总分也为 100 分。请使用 O(nlogn) 做法通过。

对于全部数据,满足导弹的高度为正整数,且不超过 5×104。

此外本题开启 spj,每点两问,按问给分。

NOIP1999 提高组 第一题


upd 2022.8.24:新增加一组 Hack 数据。

思路

对于第一个,用树状数组维护。

对于第二个,贪心用二分维护。

代码见下

#include<bits/stdc++.h>
using namespace std;
int n,m,a[1000005];
int a2[1000005],u,x,y,k,f[100005],lk=0,kl=0;
int lb(int x){
    return x&(-x);
}
void ci(int x,int d){
    while(x<=60000){
        a2[x]=max(a2[x],d);
        x+=lb(x);
    }
}
int co(int x){
    int lks=0;
    while(x>=1){
        lks=max(lks,a2[x]);
        x-=lb(x);
    }
    return lks;
}
int main(){
	while(cin>>a[n+1]){
        n++;
    }
    lk=0;
    for(int i=1;i<=n;i++){
        f[i]=co(60000-a[i])+1;
        ci(60000-a[i],f[i]);
        lk=max(lk,f[i]);
        //cout<<i<<" "<<f[i]<<" "<<a[i]<<endl;
    }
    cout<<lk<<endl;
    f[1]=a[1];
    kl++;
    for(int i=2;i<=n;i++){
        long long l=1,r=kl,md=kl+1;
        while(l<=r){
            long long mid=(l+r)/2;
            if(a[i]<=f[mid]){
                md=min(md,mid);
                r=mid-1;
            }
            else{
                l=mid+1;
            }
        }
        if(md!=kl+1){
            f[md]=a[i];
        }
        else{
            kl++;
            f[kl]=a[i];
        }
    }
    cout<<kl<<endl;
    return 0;
}

posted @ 2025-10-10 21:58  bz02_2023f2  阅读(2)  评论(0)    收藏  举报  来源