AT_abc262_g [ABC262G] LIS with Stack 题解

考虑直接模拟栈的过程。
设 \(dp_{l,r,mn,mx}\) 表示对于 \(A\) 数组 \(l\) , \(r\) 的区间内,值域为 \([mn,mx]\) 能组成的最长 \(LIS\) 长度。每次扩展肯定是往左一格扩展,也就是考虑 \(l\) 这个位置怎么处理。

  1. \(l\) 直接删掉,\(dp_{l,r,mn,mx}\leftarrow dp_{l+1,r,mn,mx}\)
  2. \(l\) 放在 \(X\) 中,则要枚举一个中间断点 \(k\) ,使得 \(l+1\) 到 \(k\) 先放入,随后放入 \(l\) ,再放入 \(k+1\) 到 \(r\) ,注意由于 \(LIS\) 的限制,必须满足 \(左半段 < A_l <右半段\) ,则 \(dp_{l,r,mn,mx}\leftarrow dp_{l+1,k,mn,a_l}+dp_{k+1,r,a_l,mx}+1\)。

代码:

#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=55;
int n;
int a[N];
int dp[N][N][N][N];
inline void add(int &x,int y){
    if(x<y) x=y;
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++){
        for(int l=1;l<=a[i];l++){
            for(int r=a[i];r<=50;r++){
                dp[i][i][l][r]=1;
            }
        }
    }
    for(int len=2;len<=n;len++){
        for(int l=1,r=len;r<=n;l++,r++){
            for(int mn=1;mn<=50;mn++){
                for(int mx=mn;mx<=50;mx++){
                    dp[l][r][mn][mx]=dp[l+1][r][mn][mx];
                    if(a[l]>=mn&&a[l]<=mx){
                        for(int k=l;k<=r;k++){
                            add(dp[l][r][mn][mx],dp[l+1][k][mn][a[l]]+dp[k+1][r][a[l]][mx]+1);
                        }
                    }
                }
            }
        }
    }
    cout<<dp[1][n][1][50];
    return 0;
}
posted @ 2026-10-08 23:28  bjq521  阅读(1)  评论(0)    收藏  举报