题意
给定一个 1 到 N 的排列 P,求 dfs 序为 P 且以 1 为根的有根树的数量(答案模 998244353)
注意对于有多个子结点的结点,按编号从小到大遍历子结点。
2≤N≤500
思路
区间 dp。
考虑设 dp[l][r] 为以 Pl 到 Pr 组成,dfs 序为 [Pl,Pr] 且以 Pl 为根的有根树数量。容易想到枚举最后遍历的子树区间 [s,t],但是题目要求按编号升序遍历,因此难以判断合法性。
容易看到答案是 使 [s,t] 添加后 dfs 序不变的有根树数量 × [s,t] 组成的有根树数量。不妨考虑另外维护 dp′[l][r] 表示将 Pr+1 添加到以 Pl 为根,由 [Pl,Pr] 组成的有根树后 dfs 序为 [Pl,Pr+1] 的方案数。易得:
dp[l,r]=∑l≤k<rdp′[l][k]×dp[k+1][r]
dp′[l,r]=∑l≤k<r,Pk+1<Pr+1dp′[l][k]×dp[k+1][r]
边界条件是 dp[l][l]=dp′[l][l]=1
时间复杂度 O(n3)
代码
#include <cstdio>
using namespace std;
const int maxn = 505;
const int mod = 998244353;
int n;
int p[maxn];
int dp[maxn][maxn][2];
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%d", &p[i]);
dp[i][i][0] = dp[i][i][1] = 1;
}
for (int l = 2; l <= n; l++)
{
for (int i = 1; i + l - 1 <= n; i++)
{
int j = i + l - 1;
for (int k = i; k <= j - 1; k++)
{
dp[i][j][0] = (dp[i][j][0] + (1ll * dp[i][k][1] * dp[k + 1][j][0])) % mod;
if (p[k + 1] < p[j + 1]) dp[i][j][1] = (dp[i][j][1] + (1ll * dp[i][k][1] * dp[k + 1][j][0])) % mod;
}
}
}
printf("%d\n", dp[1][n][0]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?