模板题:
 AcWing 1017. 怪盗基德的滑翔翼(做两次二分的优化就行)
 AcWing 1014. 登山
 
    
     
      
       
        f
       
       
        [
       
       
        i
       
       
        ]
       
       
        [
       
       
        0
       
       
        ]
       
       
        表
       
       
        示
       
       
        到
       
       
        第
       
       
        i
       
       
        个
       
       
        点
       
       
        ,
       
       
        一
       
       
        直
       
       
        上
       
       
        升
       
       
        的
       
       
        最
       
       
        大
       
       
        长
       
       
        度
       
      
      
       f[i][0]表示到第i个点,一直上升的最大长度
      
     
    f[i][0]表示到第i个点,一直上升的最大长度
 
    
     
      
       
        f
       
       
        [
       
       
        i
       
       
        ]
       
       
        [
       
       
        1
       
       
        ]
       
       
        表
       
       
        示
       
       
        到
       
       
        第
       
       
        i
       
       
        个
       
       
        点
       
       
        ,
       
       
        有
       
       
        下
       
       
        降
       
       
        段
       
       
        的
       
       
        最
       
       
        大
       
       
        长
       
       
        度
       
      
      
       f[i][1]表示到第i个点,有下降段的最大长度
      
     
    f[i][1]表示到第i个点,有下降段的最大长度
 注意
    
     
      
       
        f
       
       
        [
       
       
        i
       
       
        ]
       
       
        [
       
       
        j
       
       
        ]
       
      
      
       f[i][j]
      
     
    f[i][j]的转移方程,$
    
     
      
       
        f
       
       
        [
       
       
        i
       
       
        ]
       
       
        [
       
       
        1
       
       
        ]
       
      
      
       f[i][1]
      
     
    f[i][1]的转移要对
    
     
      
       
        f
       
       
        [
       
       
        j
       
       
        ]
       
       
        [
       
       
        0
       
       
        ]
       
       
        和
       
       
        f
       
       
        [
       
       
        j
       
       
        ]
       
       
        [
       
       
        1
       
       
        ]
       
       
        都
       
       
        要
       
       
        取
       
       
        m
       
       
        a
       
       
        x
       
      
      
       f[j][0]和f[j][1]都要取max
      
     
    f[j][0]和f[j][1]都要取max
 核心代码如下:
int main()
{
    int res = -1;
    cin >> N;
    for (int i = 1; i <= N; ++i)
    {
        cin >> h[i];
        f[i][0] = f[i][1] = 1;
        for (int j = 1; j < i; ++j)
        {
            if (h[j] < h[i])f[i][0] = max(f[i][0], f[j][0] + 1);
            if (h[j] > h[i])f[i][1] = max({f[i][1], f[j][0] + 1, f[j][1] + 1});
        }
        res = max({res, f[i][0], f[i][1]});
    }
    cout << res;
    return 0;
}
 
AcWing 482. 合唱队形 这道题和上道题一模一样
 AcWing 1012. 友好城市 这道题先排序,再求最长上升子序列
 AcWing 1016. 最大上升子序列和 暴力直接做,维护一个dp
 AcWing 1010. 拦截导弹维护两个序列就行,一个维护最长上升子序列,另一个维护个数(这个序列是单调递增的),用二分做
AcWing 187. 导弹防御系统 这道题有点难感觉,具体来说就是迭代加深,然后把每个数分别讨论放在上升子序列和下降子序列中。迭代加深模板如下:
{
	depth = 0;
	while (!DFS(1, 0, 0)) ++depth;
	cout << depth << '\n';
}
 
整道题代码如下:
#include <iostream>
using namespace std;
const int N = 55;
int n, a[N], up[N], down[N], depth;
bool DFS(int u, int sum_up, int sum_down)
{
    if (sum_up + sum_down > depth)
        return false;
    if (u == n + 1)
        return true;
    int k = 0;
    while (k < sum_up && up[k] >= a[u])
        ++k;
    int t = up[k];
    up[k] = a[u];
    if (k == sum_up && DFS(u + 1, sum_up + 1, sum_down))//需要新开
        return true;
    else if (k < sum_up && DFS(u + 1, sum_up, sum_down))//不需要新开
        return true;
    up[k] = t;
    k = 0;
    while (k < sum_down && down[k] <= a[u])
        ++k;
    t = down[k];
    down[k] = a[u];
    if (k == sum_down && DFS(u + 1, sum_up, sum_down + 1))//需要新开
        return true;
    else if (k < sum_down && DFS(u + 1, sum_up, sum_down))
        return true;
    down[k] = t;
    return false;
}
int main()
{
    while (cin >> n && n)
    {
        for (int i = 1 ; i <= n ; ++i)cin >> a[i];
        depth = 0;
        while (!DFS(1, 0, 0)) ++depth;
        printf("%d\n", depth);
    }
    return 0;
}
 
AcWing 272. 最长公共上升子序列
 
    
     
      
       
        f
       
       
        [
       
       
        i
       
       
        ]
       
       
        [
       
       
        j
       
       
        ]
       
      
      
       f[i][j]
      
     
    f[i][j]表示
    
     
      
       
        A
       
       
        [
       
       
        1
       
       
        −
       
       
        i
       
       
        ]
       
      
      
       A[1-i]
      
     
    A[1−i]与
    
     
      
       
        B
       
       
        [
       
       
        1
       
       
        −
       
       
        j
       
       
        ]
       
      
      
       B[1- j ]
      
     
    B[1−j]中以
    
     
      
       
        b
       
       
        [
       
       
        j
       
       
        ]
       
      
      
       b[j]
      
     
    b[j]结尾的最长公共上升子序列的最大长度,将集合分为不存在
    
     
      
       
        a
       
       
        [
       
       
        i
       
       
        ]
       
      
      
       a[i]
      
     
    a[i]和存在
    
     
      
       
        a
       
       
        [
       
       
        i
       
       
        ]
       
      
      
       a[i]
      
     
    a[i]的两个集合
 前者是
    
     
      
       
        f
       
       
        [
       
       
        i
       
       
        ]
       
       
        [
       
       
        j
       
       
        ]
       
       
        =
       
       
        f
       
       
        [
       
       
        i
       
       
        −
       
       
        1
       
       
        ]
       
       
        [
       
       
        j
       
       
        ]
       
      
      
       f[i][j]=f[i-1][j]
      
     
    f[i][j]=f[i−1][j]
 后者的集合又可以分为倒数第二个数分别是
    
     
      
       
        b
       
       
        [
       
       
        1
       
       
        ]
       
       
        ,
       
       
        b
       
       
        [
       
       
        2
       
       
        ]
       
       
        ⋅
       
       
        ⋅
       
       
        ⋅
       
       
        b
       
       
        [
       
       
        j
       
       
        −
       
       
        1
       
       
        ]
       
      
      
       b[1],b[2]···b[j-1]
      
     
    b[1],b[2]⋅⋅⋅b[j−1]结尾的最长公共上升子序列的长度
 下面这是优化前的版本,会
    
     
      
       
        T
       
       
        L
       
       
        E
       
      
      
       TLE
      
     
    TLE
for(int i = 1; i <= N; ++i)
    {
        for(int j = 1; j <= N; ++j)
        {
            f[i][j] = f[i - 1][j];//a[i]不包含在里面
            //下面是a[i]包含在里面
            if(A[i] == B[j])
            {
                int maxv = 1;
                for(int k = 1; k < j; ++k)
                {
                    if(B[k] < B[j])
                        maxv = max(maxv, f[i - 1][k] + 1);
                }
                f[i][j] = max(f[i][j], maxv);
            }
        }
    }
作者:北极汪汪熊
链接:https://www.acwing.com/activity/content/code/content/2060385/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
 
下面是优化后的版本,因为
    
     
      
       
        m
       
       
        a
       
       
        x
       
       
        v
       
      
      
       maxv
      
     
    maxv是一个前缀最大值
 
    
     
      
       
        ‘
       
       
        在
       
       
        这
       
       
        里
       
       
        插
       
       
        入
       
       
        代
       
       
        码
       
       
        片
       
       
        ‘
       
      
      
       `在这里插入代码片`
      
     
    ‘在这里插入代码片‘
for(int i = 1; i <= N; ++i)
    {
        int maxv=1;
        for(int j = 1; j <= N; ++j)
        {
            f[i][j] = f[i - 1][j];//a[i]不包含在里面
            if(A[i]>B[j])
                maxv=max(maxv,f[i-1][j]+1);
            //下面是a[i]包含在里面
            if(A[i] == B[j])
                f[i][j]=max(f[i][j],maxv);
        }
    }
作者:北极汪汪熊
链接:https://www.acwing.com/activity/content/code/content/2060385/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。










