题目
 

 题解
 
题解:1010. 拦截导弹(dp与贪心) - AcWing
我谈几点:
第一,由此复习了upper_bound和lower_bound函数
第二,由此学习了贪心方式求“最多分割不严格递减子序列的数目”和“最长不严格递减子序列的长度”
第三,了解到前者和“最长严格递增子序列的长度”问题的一致性
细节
 
int main()
{
    //cnt表示导弹系统数,len表示一个系统最多能拦截的导弹数
    int len = 0, cnt = 0;
    int a;
    while(cin >> a)
    {
        //pos1表示以a结尾的最长不升子序列长度-1
        int pos1 = upper_bound(f, f+len, a, greater<int>()) - f;
        if(pos1 == len) f[len ++] = a;
        else f[pos1] = a;
        int pos2 = lower_bound(g, g+cnt, a[i]) - g;
        if(pos2 == cnt) g[cnt ++] = a;
        else g[pos2] = a;
    }
    cout << len << endl;
    cout << cnt << endl;
    return 0;
}
第一个贪心:求最长不严格递减子序列长度
 
策略:如果 a 是最小,增加长度,放置于后;否则,与第一个较小值交换(因此 
     
      
       
       
         f 
        
       
      
        f 
       
      
    f 是 递减的)
  
     
      
       
       
         f 
        
       
         [ 
        
       
         p 
        
       
         o 
        
       
         s 
        
       
         1 
        
       
         ] 
        
       
         = 
        
       
         a 
        
       
      
        f[pos1] = a 
       
      
    f[pos1]=a 对应长度为  
     
      
       
       
         p 
        
       
         o 
        
       
         s 
        
       
         1 
        
       
         + 
        
       
         1 
        
       
      
        pos1+1 
       
      
    pos1+1 的,以  
     
      
       
       
         a 
        
       
      
        a 
       
      
    a 结尾的最长不严格单调递减子序列,容易知道  
     
      
       
       
         f 
        
       
      
        f 
       
      
    f 是 递减的,因此传入  
     
      
       
       
         g 
        
       
         r 
        
       
         e 
        
       
         a 
        
       
         t 
        
       
         e 
        
       
         r 
        
       
         < 
        
       
         i 
        
       
         n 
        
       
         t 
        
       
         > 
        
       
         ( 
        
       
         ) 
        
       
      
        greater<int>() 
       
      
    greater<int>(),同时为了得到第一个小于  
     
      
       
       
         a 
        
       
      
        a 
       
      
    a 的值的地址,采用  
     
      
       
       
         u 
        
       
         p 
        
       
         p 
        
       
         e 
        
       
         r 
          
       
         b 
        
       
         o 
        
       
         u 
        
       
         n 
        
       
         d 
        
       
      
        upper\;bound 
       
      
    upperbound
理解f[i]为什么被更新,明明按顺序不应该再被更新的啊:  
     
      
       
       
         f 
        
       
         [ 
        
       
         i 
        
       
         ] 
        
       
      
        f[i] 
       
      
    f[i] 要始终对应最优的序列,保持在一个最优的状态,也就是尽可能地让它的值最大,这样才能允许尽可能大的  
     
      
       
       
         a 
        
       
      
        a 
       
      
    a 值参与序列的组成。实际上它的更新,意味着原本的序列的一些值去掉了,来了一些新的值。
示例: 5 3 7 6
| a值进入考虑 | f[0] | f[1] | 
|---|---|---|
| 5 | 5(对应5) | |
| 3 | 5 | 3(对应5,3) | 
| 7 | 7(对应7) | 3 | 
| 6 | 7 | 6(对应7,6)(比5,3序列状态优) | 
所以,不同的f之间没有必然联系。
 每次都是把第一个较小值更新,就可以保证用以更新的值  
      
       
        
        
          a 
         
        
       
         a 
        
       
     a 一定只会比原对应序列的最后一个值大(前面的值可以借过来组成新序列)
第二个贪心:求最多分割不严格递减子序列的数目
 
策略: 遍历各个分割序列,如果最尾端大于等于  
     
      
       
       
         a 
        
       
      
        a 
       
      
    a ,则放置于后;否则开新序列(因此  
     
      
       
       
         g 
        
       
      
        g 
       
      
    g 递增)。
  
     
      
       
       
         g 
        
       
         [ 
        
       
         i 
        
       
         ] 
        
       
      
        g[i] 
       
      
    g[i] 对应第  
     
      
       
       
         i 
        
       
         + 
        
       
         1 
        
       
      
        i+1 
       
      
    i+1 个分割序列,表示分割序列中最小的(最后的值)。容易知道  
     
      
       
       
         g 
        
       
      
        g 
       
      
    g 是 递增的,因此不传入  
     
      
       
       
         g 
        
       
         r 
        
       
         e 
        
       
         a 
        
       
         t 
        
       
         e 
        
       
         r 
        
       
         < 
        
       
         i 
        
       
         n 
        
       
         t 
        
       
         > 
        
       
         ( 
        
       
         ) 
        
       
      
        greater<int>() 
       
      
    greater<int>(),同时为了得到第一个(最小的)大于等于  
     
      
       
       
         a 
        
       
      
        a 
       
      
    a 的值的地址,采用  
     
      
       
       
         l 
        
       
         o 
        
       
         w 
        
       
         e 
        
       
         r 
          
       
         b 
        
       
         o 
        
       
         u 
        
       
         n 
        
       
         d 
        
       
      
        lower\;bound 
       
      
    lowerbound



















