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;
}
posted @ 2021-08-23 13:22  lahlah  阅读(42)  评论(0编辑  收藏  举报