AT_abc237_f [ABC237F] |LIS| = 3 题解
分析
通过题目我们可以发现,题目里唯一难受的限制就是最长增长部分的长度。我们不妨试试将其放进状态函数里。根据 LIS 的性质,若一个长度为 \(3\) 的子序列 \(a_1,a_2,a_3\) 满足 LIS,则必有 \(a_1 <a_2<a_3\)。我们定义 \(\mathit{f}_{i,x,y,z}\) 表示在前 \(i\) 个数中,长度为 \(1\) 的 LIS 的最小 \(a_1\) 值为 \(x\),长度为 \(2\) 的 LIS 的最小 \(a_2\) 值为 \(y\),长度为 \(3\) 的 LIS 的最小 \(a_3\) 值为 \(z\)(这里的 \(a_1,a_2,a_3\) 相互独立)。
考虑从 \(i\) 扩散到 \(i+1\),有转移方程:
\[\mathit{f}_{i+1,x,y,z}=\begin{cases}\mathit{f}_{i+1,x,y,z}+\mathit{f}_{i,x',y,z}&1 \le x \le x'\\\mathit{f}_{i+1,x,y,z}+\mathit{f}_{i,x,y',z}&1 \le y \le y'\\\mathit{f}_{i+1,x,y,z}+\mathit{f}_{i,x,y,z'}&1 \le z \le z'\end{cases}
\]
这里的 \(x,y,z\) 也是独立的,如果不理解,可以看看具体的代码。
我们根据性质 \(x<y<z\),可以得到初始化:\(\mathit{f}_{0,m+1,m+2,m+3}=1\)。因为在 \(i=0\) 的时候,是可取 \(1\) 到 \(m\) 的所有。
最后的答案,就是所有的满足 \(x<y<z\) 的 \(\mathit{f}_{n,x,y,z}\) 的和。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
const int N=1005,M=15;
const int p=998244353;
int f[N][M][M][M];
void solve(){
cin>>n>>m;
f[0][m+1][m+2][m+3]=1;
for(int i=0;i<n;i++)
for(int now_x=1;now_x<=m+3;now_x++)
for(int now_y=now_x+1;now_y<=m+3;now_y++)
for(int now_z=now_y+1;now_z<=m+3;now_z++)
for(int now=1;now<=m;now++){
if(1<=now&&now<=now_x) f[i+1][now][now_y][now_z]=(f[i+1][now][now_y][now_z]+f[i][now_x][now_y][now_z])%p;
else if(now_x<now&&now<=now_y) f[i+1][now_x][now][now_z]=(f[i+1][now_x][now][now_z]+f[i][now_x][now_y][now_z])%p;
else if(now_y<now&&now<=now_z) f[i+1][now_x][now_y][now]=(f[i+1][now_x][now_y][now]+f[i][now_x][now_y][now_z])%p;
int ans=0;
for(int x=1;x<=m;x++)
for(int y=x+1;y<=m;y++)
for(int z=y+1;z<=m;z++)
ans=(ans+f[n][x][y][z])%p;
cout<<ans;return ;
}
signed main(){
solve();return 0;
}

浙公网安备 33010602011771号