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

两种做法:一种是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<<"\n"<<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<<"\n"<<p2+1; 
38 }

 

posted on 2020-04-18 16:37  很绝望  阅读(260)  评论(0编辑  收藏  举报