AT_abc262_g [ABC262G] LIS with Stack 题解
考虑直接模拟栈的过程。
设 \(dp_{l,r,mn,mx}\) 表示对于 \(A\) 数组 \(l\) , \(r\) 的区间内,值域为 \([mn,mx]\) 能组成的最长 \(LIS\) 长度。每次扩展肯定是往左一格扩展,也就是考虑 \(l\) 这个位置怎么处理。
- \(l\) 直接删掉,\(dp_{l,r,mn,mx}\leftarrow dp_{l+1,r,mn,mx}\)
- \(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;
}

浙公网安备 33010602011771号