LOJ#6495. 「雅礼集训 2018 Day1」树 题解
这个题训练的时候做了,结果只有两个人过,而且还有一个写的是状压DP……
令 dpn,d 表示n个点,最大深度为d的树的个数.
转移分为两种情况:
1、1号节点只有1个子树。此时的DP值为 dpn−1,d−1.
2、1号节点有多于一个子树。由于2号节点的父亲一定是1,我们考虑枚举2号节点所在子树的大小和最大深度然后暴力转移,复杂度 Θ(N4).
精细实现应该可以做到 Θ(N3).
至于求答案在 \mod p 意义下取整的问题,可以考虑使用long double
或__int128.
代码 :
#include <bits/stdc++.h>
#define LL __int128
using namespace std;
inline void print(LL x){
if (x > 9) print(x/10); putchar(x%10+'0');
}
inline int power(int x,int y,int P){
static int r; r = 1;
while (y){ if (y&1) r = 1ll * r * x % P; x = 1ll * x * x % P; y >>= 1; }
return r;
}
LL C[25][25],dp[25][25];
int main(){
int i,j,k,s,t;
for (i = 0; i <= 24; ++i) for (j = 0; j <= i; ++j) C[i][j] = (i==j || !i || !j) ? 1 : (C[i-1][j-1] + C[i-1][j]);
dp[1][1] = 1;
for (i = 2; i <= 24; ++i)
for (j = 1; j <= 24; ++j){
dp[i][j] = dp[i-1][j-1];
for (s = 1; s <= i-2; ++s){
for (t = 1; t <= s && t < j-1; ++t) dp[i][j] += C[i-2][s-1] * dp[s][t] * dp[i-s][j];
LL tot = 0;
for (k = 1; k <= j; ++k) tot += dp[i-s][k];
dp[i][j] += C[i-2][s-1] * dp[s][j-1] * tot;
}
}
int P,n; cin >> n >> P;
LL sumd = 0,frac = 1;
for (i = 1; i <= n; ++i) sumd += i * dp[n][i];
for (i = 1; i < n; ++i) frac *= i;
print((sumd * 2 + frac) / frac / 2),putchar('\n');
sumd = sumd % P * power(frac % P,P-2,P) % P;
print(sumd),putchar('\n');
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 《HelloGitHub》第 106 期
· 数据库服务器 SQL Server 版本升级公告
· 深入理解Mybatis分库分表执行原理
· 使用 Dify + LLM 构建精确任务处理应用