zoukankan      html  css  js  c++  java
  • Luogu P1020 导弹拦截

    题目描述

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

      输入导弹依次飞来的高度(雷达给出的高度数据是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
    ", 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
    ", 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)
  • 相关阅读:
    HDU 2141.Can you find it?-二分
    POJ 3258.River Hopscotch-二分
    HDU 1213.How Many Tables-并查集
    HDU 1232.畅通工程-并查集
    hdu 5701 中位数计数 思路题
    codeforces 354 div2 C Vasya and String 前缀和
    codeforces 11 B.Jumping Jack 想法题
    hdu 2204 Eddy's爱好 容斥原理
    xtu 1242 Yada Number 容斥原理
    codeforces 300 div2 B.Pasha and Phone 容斥原理
  • 原文地址:https://www.cnblogs.com/kcn999/p/10803126.html
Copyright © 2011-2022 走看看