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

    题目地址

    最多能拦截的导弹数为最长不上升子序列的长度

    根据$dilworth$定理(偏序集所能划分成的最少的全序集的个数等于最大反链的元素个数)可以得到第二问的答案就是最长上升子序列的长度。

    $ n le 100000 $ 因此$O(n^{2})$的算法不能得全分,这里讲解$O(nlog{n})$的算法。

    假设我们要求某序列的最长不上升子序列的长度。

    我们设置两个数组,$a$与$c$,$a[i]$代表序列的第$i$个元素,$c[i]$表示长度为$i$的不上升子序列的最后一位的最大值。

    再设置一个变量$len$,为$c$数组的长度。

    从1到$n$扫描数组$a$

    检查$a[i]$是否小于等于$c[len]$,如果是,则$c[++len] = a[i]$

    如果否,那么寻找$c$中第一个小于$a[i]$的数,并将其替换成$a[i]$。
    如果按照朴素的查找方法,寻找第一个小于$a[i]$的数所需时间复杂度为$O(n)$,这样算法整体复杂度仍为$O(n^2)$,我们需要对其进行优化。

    我们会发现,因为我们找的是第一个小于$a[i]$的数,因此$c$数组是满足二分性的,可以使用二分查找。这样一次查找的时间复杂度就降为了$O(log{n})$,整体的时间复杂度为$O(nlog{n})$。

    我们要尽可能让每一个$c[i]$尽量大,因为不下降子序列的最后一位越大,后面能选择的数就越多。

    函数lower_bound upper_bound

    lower_bound与upper_bound的作用就是二分查找,lower_bound可以找到第一个大于等于某个数的数,upper_bound可以找到第一个大于某个数的数,她们的返回值为查找到的数的指针,如需获得这个数的位置,可以用获得的指针减去数组开头的指针。如需获得这个数,直接设置一个指针存下来就行

    $eg:$
    我们要在数组$b$中找到第一个大于等于$x$的数$p$。($b$的长度为$m$)

    *p = lower_bound(b,b + m,x);

    则$*p$就是这个数

    p = lower_bound(b,b + m,x) - b;

    则$b[p]$就是这个数。

    upper_bound的使用方法同上

    注意,lower_bound和upper_bound只能在升序序列里使用。

    那么我们想要在一个降序序列里找到第一个小于等于或小于$x$的数该怎么办呢?
    我们可以修改一下lower_bound或upper_bound,加上$cmp$函数,或使用$greater<int>()$

    $eg:$

    *p = lower_bound(b,b + m,x,greater<int>);
      
      
    bool cmp(const int& a,const int& b) {
          return a > b;
    }
    
    *p = lower_bound(b,b + m,x,cmp);

    $Code:$

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    
    using namespace std;
    
    const int MAXN = 100010;
    
    int len1,len2,n;
    int a[MAXN],f1[MAXN],f2[MAXN];
    
    int main() {
        while(cin >> a[++n]);n--;
        len1 = len2 = 1;
        f1[1] = f2[1] = a[1];
        for(int i = 2; i <= n; i++) {
            if(a[i] <= f1[len1]) {
                f1[++len1] = a[i];
            }
            else {
                int p = upper_bound(f1 + 1,f1 + len1 + 1,a[i],greater<int>()) - f1;
                f1[p] = a[i];
            }
            if(a[i] > f2[len2]) {
                f2[++len2] = a[i];
            }
            else {
                int p = lower_bound(f2 + 1,f2 + len2 + 1,a[i]) - f2;
                f2[p] = a[i];
            }
        }
        cout << len1 << endl << len2 << endl;
        return 0;
    }
  • 相关阅读:
    LSMW TIPS
    Schedule agreement and Delfor
    Running VL10 in the background 13 Oct
    analyse idoc by creation date
    New Journey Prepare
    EDI error
    CBSN NEWS
    Listen and Write 18th Feb 2019
    Microsoft iSCSI Software Target 快照管理
    通过 Microsoft iSCSI Software Target 提供存储服务
  • 原文地址:https://www.cnblogs.com/kjd123456/p/12446915.html
Copyright © 2011-2022 走看看