Luogu 1020 导弹拦截(动态规划,最长不下降子序列,二分,STL运用,贪心,单调队列)

Luogu 1020 导弹拦截(动态规划,最长不下降子序列,二分,STL运用,贪心,单调队列)

Description

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

输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

Input

一行,若干个正整数最多100个。

Output

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

Sample Input

389 207 155 300 299 170 158 65

Sample Output

6
2

Http

Luogu:https://www.luogu.org/problem/show?pid=1020

Source

二分,贪心,最长不下降子序列,单调队列

解决思路

第一问比较容易理解,就是求最长不上升子序列。动态规划的方法可以过,但复杂度是n^2的,这里介绍另外一种方法。
首先想清楚一点,求最长不上升子序列就是求倒序的最长不下降子序列。
首先来讲一下操作吧:我们用一个vector(下面命名为Arr)来进行操作,具体如下:
从后往前扫描导弹的高度,设当前高度为x,那么若Arr为空或Arr的最后一个数比x小,则直接把x放到Arr尾部。
否则,找到第一个大于x的数,将其用x替换。
这个方法为什么是对的呢?它是基于贪心的思想,就是要使得Arr中的数尽量小(因为要求最长嘛),如果实在不行,就把Arr的长度+1,把这个数直接放到尾部。
那么关于查找操作,因为从上面的操作可以看出,我们保证了Arr的有序性,所以我们就可以用二分查找来完成。笔者这里使用的是STL中的lower_bound函数,它返回的是第一个满足大于等于x的数的位置,而因为我们这里是求最长不下降子序列,所以我们还要用一个while来找到第一个大于x的数的位置。

那么第二问怎么求呢?
其实,第二问就是求最长上升子序列的长度(正序的)。具体方法和上面一样,只是不要取等。这里讲一下为什么。
我们根据最长上升子序列的性质并结合本题特征可以知道,最长上升子序列的中的每一个元素一定就是每一个系统最后打的那一个导弹,这可以由反证法得知。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;

const int maxN=200;
const int inf=2147483647;

int n;
int Height[maxN];
vector<int> Arr;

int main()
{
    n=1;
    while (cin>>Height[n])
        n++;
    n--;
    Arr.clear();
    vector<int>::iterator Find;
    for (int i=n;i>=1;i--)//第一问,求倒序的最长不下降子序列
    {
        if ((Arr.size()==0)||(Arr[Arr.size()-1]<=Height[i]))//注意这里可以取等
            Arr.push_back(Height[i]);
        else
        {
            Find=lower_bound(Arr.begin(),Arr.end(),Height[i]);
            while (*Find==Height[i])//这里的while是求出第一个大于Height[i]的
                Find++;
            *Find=Height[i];
        }
    }
    cout<<Arr.size()<<endl;
    Arr.clear();
    for (int i=1;i<=n;i++)//第二问,求最长递增子序列
    {
        if ((Arr.size()==0)||(Arr[Arr.size()-1]<Height[i]))//注意这里不能取等
            Arr.push_back(Height[i]);
        else
        {
            Find=lower_bound(Arr.begin(),Arr.end(),Height[i]);
            *Find=Height[i];
        }
    }
    cout<<Arr.size()<<endl;
    return 0;
}
posted @ 2017-07-19 18:22  SYCstudio  阅读(925)  评论(0编辑  收藏  举报