LOJ #6495. 「雅礼集训 2018 Day1」树
https://loj.ac/p/6495
第一问打个表即可
重点是第二问
注意到2点父亲一定是1,考虑从这个固定关系入手
设
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示i个点,深度为j的树个数
转移就考虑最深的节点是在2的子树中还是在1的其他子树中
code:
#include<bits/stdc++.h>
#define N 405
#define ll long long
using namespace std;
int n, mod, c[N][N], E[N] = {0,1,2,3,3,3,4,4,4,4,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6};
ll f[N][N];
ll qpow(ll x, ll y) {
ll ret = 1;
for(; y; y >>= 1, x = x * x % mod) if(y & 1) ret = ret * x % mod;
return ret;
}
int main() {
scanf("%d%d", &n, &mod); printf("%d\n", E[n]);
for(int i = 0; i <= n; i ++) c[i][0] = 1;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= i; j ++) c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
f[1][1] = 1;
for(int i = 2; i <= n; i ++)
for(int j = 2; j <= i; j ++)
for(int x = 1; x < i; x ++) {
ll ret = 0;
for(int y = 1; y <= j - 2; y ++) ret += f[i - x][j] * f[x][y], ret %= mod;
for(int y = 1; y <= j; y ++) ret += f[i - x][y] * f[x][j - 1], ret %= mod;
(f[i][j] += c[i - 2][x - 1] * ret) %= mod;
}
ll ans = 0;
for(int i = 1; i <= n; i ++) ans += 1ll * i * f[n][i], ans %= mod;
for(int i = 1; i <= n - 1; i ++) ans = ans * qpow(i, mod - 2) % mod;
printf("%lld", ans);
return 0;
}