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

    P1020 导弹拦截

       知识铺垫:

      upper_bound(f+1,f+n+1,key)-f返回在不降序列f中大于key的第一个元素的下标

      lower_bound(f+1,f+n+1,key)-f返回在不降序列f中大于等于key的第一个元素的下标

      如果要在非升序列(小于和小于等于)中使用这两个函数,就需要重载运算符

        bool cmp(const int& a,const int& b){return a > b;} 

    • 最长上升子序列问题(Longest Increasing Subsequence,LIS):给定一个长度为n的序列a,求数值单调递增的子序列的长度最长是多少。a的任意子序列b可表示为b={a[k1],a[k2],...,a[kp]},其中k1<k2<...<kp。
      • O(n^2)求法:f[i]表示以a[i]为结尾的LIS的长度。则有f[i]=max{f[j]+1},0<j<i,a[j]<a[i],边界:f[0]=0。目标:max(f[i]},1<=i<=n。
      • O(nlogn)求法:f[i]表示长度为i的LIS的结尾元素,初始化ans=0,从1到n遍历a,每遇到a[i]>f[ans],就使f[++ans]=a[i]。否则:根据f[]的定义可知,f[]数组是单调递增的,所以可以用二分查找找到p使得f[p]>=a[i],f[p-1]<a[i]令f[p]=a[i](用lower_bound()即可),即找到第一个大于等于a[i]的f[p](lower_bound),令f[p]=a[i](因为a[i]的潜力更大),平均复杂度logn,所以总时间复杂度为nlogn
    • 最长下降子序列:查找时找第一个小于等于a[i]的元素(因为此时f[]序列是非升的,所以需要重载运算符,用lower_bound)
    • 最长不下降:a[i]>=f[ans] 则f[++ans]=a[i],否则找到第一个大于a[i]的f[p](upper_bound),
    • 最长不上升:a[i]<=f[ans] 则f[++ans]=a[i],否则找到第一个小于a[i]的f[p](也需要重载运算符,用upper_bound),

    题意:

    给一个长度不超过100000的数列,其中每一个数都是不超过50000的正整数,第一问求这个序列的最长不上升子序列,第二问求将这个序列分为n个不上升子序列时n的最小值。

       解题思路:

      1. 第一问:直接求最长不上升子序列即可。

      2. 第二问:可以用贪心或者有一个Dilworth定理,可知直接求该序列的最长上升子序列的长度即可。

      代码:

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 #include <cstring>
     5 #include <cctype>
     6 using namespace std;
     7 
     8 #define res register int
     9 inline int read()
    10 {
    11     int x(0),f(1); char ch;
    12     while(!isdigit(ch=getchar())) if(ch=='-') f=-1;
    13     while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    14     return f*x;
    15 }
    16 
    17 const int N=100000+10; 
    18 int f1[N],f2[N],a[N],n,ans1,ans2;
    19 inline bool cmp(const int&a,const int&b){return a>b;}
    20 
    21 int main()
    22 {
    23     while(~scanf("%d",&a[++n]));
    24     n--;
    25     f1[1]=f2[1]=a[1]; ans1=ans2=1;
    26     for(res i=2 ; i<=n ; i++)
    27     {
    28         if(a[i]<=f1[ans1]) 
    29             f1[++ans1]=a[i];
    30         else 
    31             *upper_bound(f1+1,f1+ans1+1,a[i],cmp)=a[i];
    32         if(a[i]>f2[ans2]) 
    33             f2[++ans2]=a[i];
    34         else
    35             *lower_bound(f2+1,f2+ans2+1,a[i])=a[i];
    36     }
    37     printf("%d
    %d
    ",ans1,ans2);
    38     return 0;
    39 }
    View Code
  • 相关阅读:
    高效 Java Web 开发框架 JessMA v3.2.3 正式发布
    跨平台日志清理工具 Log-Cutter v2.0.1 RC-1 发布
    跨平台日志清理工具 Log-Cutter v1.0.3 正式发布
    高性能 Windows Socket 组件 HP-Socket v2.2.3 正式发布
    7. Oracle数据加载和卸载
    6. Oracle闪回特性
    5. RAMN备份与恢复
    4. Oracle数据库用户管理备份与恢复
    3. Oracle数据库逻辑备份与恢复
    后台系统依据路由生成tabs标签页
  • 原文地址:https://www.cnblogs.com/wmq12138/p/10363793.html
Copyright © 2011-2022 走看看