洛古 P1020 导弹拦截 (贪心+二分)

题目描述
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度(雷达给出的高度数据是 ≤50000 \le 50000≤50000 的正整数),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入输出格式

输入格式:
111 行,若干个整数(个数 ≤100000 \le 100000≤100000 )

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

输入输出样例
输入样例#1:
389 207 155 300 299 170 158 65

输出样例#1:
6
2

题意:很明了让你求最长不上升子序列 和 最长上升子序列,主要的坑点就在于要分析好逻辑,二分函数要写好,也可以直接用c++的内置函数

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int maxn = 1e5+5;
const int INF = 0x3f3f3f3f;
int v[maxn];
int low[maxn],high[maxn];
int pos1,pos2;

int bin_search1(int *a,int r,int x)//返回a数组中第一个小于等于x的位置
{
    int l=1,mid;
    while(l<=r)
    {
        mid=(l+r)>>1;
        if(a[mid]>=x)
            l=mid+1;
        else
            r=mid-1;
    }
    return l;
}

//int bin_search2(int *a,int r,int x)//返回a数组中第一个大于等于x的位置
//{
//    int l=1,mid;
//    while(l<=r)
//    {
//        mid=(l+r)>>1;
//        if(a[mid]<x)
//            l=mid+1;
//        else 
//            r=mid-1;
//    }
//    return l;
//}

int main() {
    int s = 1;
    while(cin>>v[s]) s++;
    s--; pos1 = 1;pos2 = 1;
    memset(low,INF,sizeof(low)); memset(high,0,sizeof(high));
    high[pos1] = v[1];
    for (int i = 2;i<=s;i++) { //最长上升 
        if ( v[i]>high[pos1] ) {
            pos1++;
            high[pos1] = v[i];
        } else {
            *lower_bound(high+1,high+pos1+1,v[i]) = v[i];
        }
    }
    low[1] = v[1];
    for (int i = 2;i<=s;i++) { //最长不上升 
        if ( v[i]<=low[pos2] ) {
            pos2++;
            low[pos2] = v[i];
        } else {
            low[bin_search1(low,pos2,v[i])] = v[i];
        }
    } 
    printf("%d\n%d\n",pos2,pos1);
    return 0;

}

猜你喜欢

转载自blog.csdn.net/Acer12138/article/details/81360251