|LIS| = 3(最长上升子序列,DP)
题意
求满足下列条件的序列个数:
- 长度为
- 序列的每个元素值都在
- 最长严格上升子序列的长度恰好为
数据范围
思路
首先回顾一下最长上升子序列的做法:
- 维护一个vector,记为
- 对于每个元素,找到满足的最小元素的下标(二分)。如果存在的话,用替换。否则,将添加到的后面。
- 最终的长度。
因为我们只关心长度小于等于的最长上升子序列。因此考虑,前项的序列中长度为,,的最长上升子序列中结尾的最小值为,,的数量。
转移的过程中,枚举第个元素的数值,记为。若,那么可以替换,则;若,那么可以替换,则;若,那么可以替换,则。
这里需要注意一点,就是若,表示长度为的最长上升子序列不存在。同理。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int mod = 998244353, N = 1010, M = 15;
int n, m;
ll f[N][M][M][M];
int main()
{
scanf("%d%d", &n, &m);
f[0][m + 1][m + 1][m + 1] = 1;
for(int i = 1; i <= n; i ++) {
for(int a = 1; a <= m + 1; a ++) {
for(int b = 1; b <= m + 1; b ++) {
for(int c = 1; c <= m + 1; c ++) {
for(int x = 1; x <= a && x <= m; x ++) {
f[i][x][b][c] = (f[i][x][b][c] + f[i - 1][a][b][c]) % mod;
}
for(int x = a + 1; x <= b && x <= m; x ++) {
f[i][a][x][c] = (f[i][a][x][c] + f[i - 1][a][b][c]) % mod;
}
for(int x = b + 1; x <= c && x <= m; x ++) {
f[i][a][b][x] = (f[i][a][b][x] + f[i - 1][a][b][c]) % mod;
}
}
}
}
}
ll ans = 0;
for(int i = 1; i <= m; i ++) {
for(int j = 1; j <= m; j ++) {
for(int k = 1; k <= m; k ++) {
ans = (ans + f[n][i][j][k]) % mod;
}
}
}
printf("%lld\n", ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!