首页 > 其他 > 详细

【题解】导弹拦截

时间:2019-05-02 19:57:31      阅读:101      评论:0      收藏:0      [点我收藏+]

题目描述

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

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

 

输入格式

  1行,若干个整数(个数100000)。

 

输出格式

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

 

输入样例

389 207 155 300 299 170 158 65

 

输出样例

6

2

 

题解

  这题在洛谷上被强化了,所以$O(n^{2})$的暴力过不了。

  先说暴力做法,第一问就是求最长不上升子序列的版,dp就好。注意最大值不一定是$dp[n]$。

  第二问是一个贪心。假设我们记录第$1$到第$i$个导弹至少需要$cnt$个系统拦截,其中$f[j]$表示第$j$个系统最后拦截到的导弹高度。

  那么,当我们枚举到第$i$导弹时,我们可以枚举$f[j]$,如果所有$f[j]$都小于$a[i]$,那么我们就让$f[++cnt] = a[i]$,即多分配一个系统。

  如果有多个$f[j]$满足$f[j]>=a[i]$,我们就让其中最小的$f[j] = a[i]$即可。

技术分享图片
#include <iostream>
#include <cstdio>

#define MAX_N (100000 + 5)

using namespace std;

int n;
int a[MAX_N];
int dp[MAX_N], ans;
int f[MAX_N], cnt;

int main()
{
    while(~scanf("%d", a + n + 1)) ++n;
    for(register int i = 1; i <= n; ++i)
    {
        for(register int j = 1; j < i; ++j)
        {
            if(a[i] <= a[j]) dp[i] = max(dp[i], dp[j]);
        }
        ++dp[i];
        ans = max(ans, dp[i]);
    }
    printf("%d\n", ans);
    int p;
    f[0] = 2147483647;
    for(register int i = 1; i <= n; ++i)
    {
        p = 0;
        for(register int j = 1; j <= cnt; ++j)
        {
            if(a[i] <= f[j] && f[j] < f[p]) p = j;
        }
        if(!p) p = ++cnt;
        f[p] = a[i];
    }
    printf("%d", cnt);
    return 0;
}
参考程序O(n^2)

   这个时候我们观察第一问的dp,其实这里看作求$a[n]$到$a[1]$的最长不下降子序列,这样就可以用树状数组找最大值来解决了。

  观察第二问,其实是Dilworth定理,也就是求最长上升子序列,再用树状数组即可。

技术分享图片
#include <iostream>
#include <cstring>
#include <cstdio>

#define MAX_N (100000 + 5)
#define MAX_A (50000 + 5) 

#define lowbit(x) ((x) & -(x))

using namespace std;

int n;
int a[MAX_N];
int maxa;
int ans;
int t[MAX_N];

int main()
{
    while(~scanf("%d", a + n + 1)) maxa = max(maxa, a[++n]);
    int tmp;
    for(register int i = n; i; --i)
    {
        tmp = 0;
        for(register int j = a[i]; j; j -= lowbit(j))
        {
            tmp = max(tmp, t[j]);
        }
        ++tmp;
        ans = max(ans, tmp);
        for(register int j = a[i]; j <= maxa; j += lowbit(j))
        {
            t[j] = max(t[j], tmp);
        }
    }
    printf("%d\n", ans);
    memset(t, 0, sizeof t);
    ans = 0;
    for(register int i = 1; i <= n; ++i)
    {
        tmp = 0;
        for(register int j = a[i] - 1; j; j -= lowbit(j))
        {
            tmp = max(tmp, t[j]);
        }
        ++tmp;
        ans = max(ans, tmp);
        for(register int j = a[i]; j <= maxa; j += lowbit(j))
        {
            t[j] = max(t[j], tmp);
        }
    }
    printf("%d", ans);
    return 0;
}
参考程序O(nlogn)

 

【题解】导弹拦截

原文:https://www.cnblogs.com/kcn999/p/10803126.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!