导弹拦截(题解)(优化)

题目:

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

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

Input

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

Output

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

思路:

最长和最长不升序子序列问题。

最多拦截《==》最长不上升序子序列。

最少需要多少系统拦截《==》最长上升子序列

优化:

比如最长上升子序列问题,对于a[i]以前的子序列,当a[k]<a[i](k<i)时,dp[i]=max(dp[k]+1,dp[i]),但时间复杂度高。可以记录每种长度的子序列最后一个数(建一个数组b[],他的数是严格递增的),当a[i]>b[j],a[i]就可以排在b[j]后边,找到满足a[i]>b[j]条件的最后一个j,b[j+1]=a[i],长度len=max(len,j+1),最后答案即为len(len为最长子序列有多少个数;

最长不上升序子序列一样,当a[i]<=b[j],a[i]就可以排在b[j](他的数是不上升的)后边,找到满足a[i]>b[j]条件的最后一个j,b[j+1]=a[i],长度len=max(len,j+1),最后答案即为len(len为最长不上升序子序列有多少个数);

需要注意b[0]的取值,他一定要让a[i]满足和b[j]关系,比如最长子序列a[i]>b[0],最长不升a[i]<=b[0];

代码:

#define _CRT_SECURE_NO_WARNINGS 
#include <iostream>
#include <queue>
#include<algorithm>
#include<cmath>
#include<map>
#include<string.h>
#include<string>
#include<cstring>
using namespace std;
const long long N=1e6;
const long long MAX = 1e13;
long long n,m, a[N],b[N],l,r,mid,c[N],ans,cnt;
int main()
{
    while (cin >> ans)
        a[++cnt] = ans;
    long long len = 0;
    long long len1 = 0;
    b[0] = -MAX;
    for (int i = 1; i <= cnt; i++)
    {
        l = 0;
        r = len;
        while (l <= r)
        {
            mid = (l + r) / 2;
            if (b[mid] < a[i])
                ans = mid, l = mid + 1;
            else
                r = mid - 1;
        }
        b[ans + 1] = a[i];
        len = max(len, ans + 1);
    }
    c[0] = MAX;
    for (int i = 1; i <= cnt; i++)
    {
        l = 0;
        r = len1;
        while (l <= r)
        {
            mid = (l + r) / 2;
            if (a[i] <= c[mid])
                ans = mid, l = mid + 1;
            else
                r = mid - 1;
        }
        c[ans + 1] = a[i];
        len1 = max(len1, ans + 1);
        
    }
    cout << len1 << endl;
    cout << len << endl;
     return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值