AT_abc237_f [ABC237F] |LIS| = 3 题解

AT_abc237_f [ABC237F] |LIS| = 3 题解

洛谷

题意够简练了,不复述。

避坑

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

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

思路

胖头鱼教练:看题吧。

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

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

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

那么想想算法。

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

fi,l1,l2,l3 表示当前考虑到前 i 个数,长度为 1 的最大数是 l12 的最大数是 l23 的最大数是 l3 的答案。

那么看看状态转移方程。

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

{ fi,v,l2,l3=fi,v,l2,l3+fi1,l1,l2,l3  (vl1) fi,l1,v,l3=fi,l1,v,l3+fi1,l1,l2,l3  (l1<vl2) fi,l1,l2,v=fi,l1,l2,v+fi1,l1,l2,l3  (l2<vl3)

最后的答案显然是 i=1mj=i+1mk=j+1mfn,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 @   Atserckcn  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
点击右上角即可分享
微信分享提示