AT_abc237_f [ABC237F] |LIS| = 3 题解

AT_abc237_f [ABC237F] |LIS| = 3 题解

洛谷

题意够简练了,不复述。

避坑

注意,洛谷的翻译有误,数列各项可以等于 \(M\),不是 \(M\)​ 以下!!

而且 “最长增加部分列” 最好改为 “最长上升子序列”。

思路

胖头鱼教练:看题吧。

我:怎么动态维护最长上升子序列长度啊……

这时,注意到我们维护最长上升子序列长度并不关心序列所有数是多少

那么我们可以把最长上升子序列长度分别是 \(1\)\(2\)\(3\) 序列中的最大数维护出来,因为我们如果要更新最长上升子序列只看最大数。

那么想想算法。

这题我是从 dp 专题里看到的,所以当然是 dp 喽。

\(f_{i,l1,l2,l3}\) 表示当前考虑到前 \(i\) 个数,长度为 \(1\) 的最大数是 \(l1\)\(2\) 的最大数是 \(l2\)\(3\) 的最大数是 \(l3\) 的答案。

那么看看状态转移方程。

对于我们当前要插入的数字 \(v\),考虑它可以插在哪里——

\[\left\{ \begin{aligned} &\ f_{i,v,l2,l3}=f_{i,v,l2,l3}+f_{i-1,l1,l2,l3}\ \ (v\le l1)& \\ &\ f_{i,l1,v,l3}=f_{i,l1,v,l3}+f_{i-1,l1,l2,l3}\ \ (l1< v\le l2)& \\ &\ f_{i,l1,l2,v}=f_{i,l1,l2,v}+f_{i-1,l1,l2,l3}\ \ (l2< v\le l3)& \end{aligned} \right. \]

最后的答案显然是 \(\sum^m_{i=1}\sum^m_{j=i+1}\sum_{k=j+1}^{m} f_{n,i,j,k}\)

AC CODE:

#include<bits/stdc++.h>
using namespace std;
#define ljl long long
const ljl N=1001,mod=998244353;
ljl n,m,f[N][15][15][15],ans;
int main(){
	ios::sync_with_stdio(0);
	cin>>n>>m;
	f[0][m+1][m+1][m+1]=1;
	for(ljl i=1;i<=n;++i)
	{
		for(ljl v=1;v<=m;++v)
		{
			for(ljl l1=1;l1<=m+1;++l1)
			{
				for(ljl l2=l1;l2<=m+1;++l2)
				{
					for(ljl l3=l2;l3<=m+1;++l3)
					{
						if(v<=l1)
							f[i][v][l2][l3]=(f[i][v][l2][l3]+f[i-1][l1][l2][l3])%mod;
						else
						{
							if(v<=l2)
								f[i][l1][v][l3]=(f[i][l1][v][l3]+f[i-1][l1][l2][l3])%mod;
							else
								if(v<=l3)
									f[i][l1][l2][v]=(f[i][l1][l2][v]+f[i-1][l1][l2][l3])%mod;
						}
					}
				}
			}
		}
	}
	for(ljl i=1;i<=m;++i)
		for(ljl j=1;j<=m;++j)
			for(ljl k=1;k<=m;++k)
				ans=(ans+f[n][i][j][k])%mod;
	cout<<ans<<'\n';
	return 0;
}
posted @ 2025-02-23 18:18  Atserckcn  阅读(25)  评论(0)    收藏  举报