zoukankan      html  css  js  c++  java
  • 洛谷1102导弹拦截

    这一题分为两个问题,一个是一台最多能射下多少枚导弹,一个是需要多少太拦截设备,第一个问很容易知道就是求最长不递增子序列,第二问就是求最长上升子序列,我们稍微证明一下第二问,因为导弹拦截只能拦截越来越低的,所以遇到比当前高的时候就要重新加一台,最长上升子序列的长度就是至少需要的台数,子序列中每一颗导弹都不能用同一拦截器拦截。

    两种做法:一种是N方的做法,我们可以发现一台设备已经拦截了K枚导弹,能否拦截第K+1枚,就要比较第K+1枚导弹和最后一枚导弹的高度,我们只要dp[i],表示如果i作为最后一颗拦截的导弹最长有多少,它可以由dp[j]决定,j<i而且a[j]>=a[i],实际含义就是在i前面找比第i颗导弹高的导弹,然后任意一个比第i颗导弹高的导弹后面,所以存在下面的状态转移方程:

     for(int i=1;i<cnt;i++)
      for(int j=1;j<i;j++)
       if(a[j]>=a[i])
        dp[i]=max(dp[j]+1,dp[i]);

    第二问求法类似,我们同样每种情况只考虑结尾:代码如下

    #include<iostream>
    using namespace std;
     int a[100001],dp[100001],dp1[100001];
    int main()
    {
       int cnt=1;
       while(cin>>a[cnt])
        cnt++;
       for(int i=1;i<cnt;i++) dp1[i]=1,dp[i]=1; 
        for(int i=1;i<cnt;i++)
          for(int j=1;j<i;j++)
          {
             if(a[j]>=a[i])
                dp[i]=max(dp[j]+1,dp[i]);
             else 
                 dp1[i]=max(dp1[j]+1,dp1[i]);
           }
       int ans=0,ans2=0;
       for(int i=1;i<=cnt;i++)
       {
          ans=max(ans,dp[i]);
          ans2=max(ans2,dp1[i]);
       }
       cout<<ans<<"
    "<<ans2; 
    }
    

      

    第二种做法叫做在线处理,我们dp[i]代表第i颗导弹能够拦截的最大高度,维护一个单调数组,当进来的那颗导弹比最后一刻导弹低时加入队列,当比他高时,我们看它最多前面能继承的多少颗导弹,在队列中二分找到第一个比他小的数字,替代掉;

     1 #include<iostream>
     2 using namespace std;
     3 int a[100001],dp[100001],dp1[100001];
     4 //在线处理,我们考虑每个位置打那个更好,维护一个单调子序列 
     5 int main()
     6 {
     7     int cnt=0,p1=0,p2=0;
     8     while(cin>>a[cnt]) cnt++;
     9     dp[0]=a[0],dp1[0]=a[0];
    10     for(int i=1;i<cnt;i++)
    11     {
    12         if(dp[p1]>=a[i]) dp[++p1]=a[i];
    13         else
    14         {
    15             int l=0,r=p1;
    16             while(l<r)//在里面找第一个小于它的数 
    17             {
    18                 int mid=(l+r)>>1;
    19                 if(dp[mid]<a[i]) r=mid;
    20                 else l=mid+1; 
    21             }
    22             dp[l]=a[i];
    23         }
    24         if(dp1[p2]<a[i]) dp1[++p2]=a[i];
    25         else
    26         {
    27             int l=0,r=p2;//在这里面找第一个大于等于它的数 
    28             while(l<r)
    29             {
    30                 int mid=(l+r)>>1;
    31                 if(dp1[mid]>=a[i]) r=mid;
    32                 else l=mid+1;
    33             }
    34             dp1[l]=a[i];
    35          } 
    36      } 
    37      cout<<p1+1<<"
    "<<p2+1; 
    38 }
  • 相关阅读:
    ListView的CheckBox实现全部选中/不选中
    JTA 深度历险
    缓存更新的套路是怎样的?
    对ThreadLocal实现原理的一点思考
    透彻理解Spring事务设计思想之手写实现
    JAVA 线程池架构浅析
    ThreadPoolExecutor 线程池浅析
    MySql实现sequence功能的代码
    MySql事务select for update及数据的一致性处理讲解
    MySQL四种事务隔离级别详解
  • 原文地址:https://www.cnblogs.com/hjw201983290498/p/12726605.html
Copyright © 2011-2022 走看看