• luoguP4492 [HAOI2018]苹果树 组合计数 + dp



    首先,每个二叉树对应着唯一的中序遍历,并且每个二叉树的概率是相同的

    这十分的有用

    考虑(dp)求解

    (f_i)表示(i)个节点的子树,根的深度为(1)时,所有点的期望深度之和(乘(i!))的值

    (g_i)表示(i)个节点的子树,期望两两路径之和(乘(i!))的值

    那么(f_i = i * i! + sum limits_{L = 0}^{i - 1} inom{i - 1}{L} (f_L * R! + f_R * L!))(L, R)分别表示左右子树的值

    (g_i = sum limits_{L = 0}^{i - 1} inom{i - 1}{L} (g_L * R! + g_R * L! + f_L * R! * (R + 1) + f_R * L! * (L + 1)))

    复杂度(O(n^2))

    由于没有逆元,因此组合数要预处理


    好像可以用多项式优化到(O(n log^2 n))QAQ


    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    #define ri register int
    #define rep(io, st, ed) for(ri io = st; io <= ed; io ++)
    #define drep(io, ed, st) for(ri io = ed; io >= st; io --)
    
    const int sid = 2e3 + 5;
    
    int n, mod;
    int C[sid][sid], fac[sid], f[sid], g[sid];
    
    inline void inc(int &a, int b) { a += b; if(a >= mod) a -= mod; }
    inline void dec(int &a, int b) { a -= b; if(a < 0) a += mod; }
    inline int Inc(int a, int b) { return (a + b >= mod) ? a + b - mod : a + b; }
    inline int Dec(int a, int b) { return (a - b < 0) ? a - b + mod : a - b; }
    inline int mul(int a, int b) { return 1ll * a * b % mod; }
    
    inline void init() {
        fac[0] = C[0][0] = 1;
        rep(i, 1, n) {
            C[i][0] = C[i][i] = 1;
    		fac[i] = mul(fac[i - 1], i);
            rep(j, 1, i - 1) C[i][j] = Inc(C[i - 1][j], C[i - 1][j - 1]);
        }
    }
    
    inline void dp() {
        f[1] = 1;
        rep(i, 2, n) {
            rep(L, 0, i - 1) {
                int R = i - 1 - L, F = 0, G = 0;
    			F = (1ll * f[L] * fac[R] + 1ll * f[R] * fac[L]) % mod;
                G = (1ll * f[L] * fac[R] % mod * (R + 1) % mod);
    			inc(G, 1ll * f[R] * fac[L] % mod * (L + 1) % mod);
    			inc(G, 1ll * g[L] * fac[R] % mod);
    			inc(G, 1ll * g[R] * fac[L] % mod);
                inc(f[i], mul(F, C[i - 1][L])); inc(g[i], mul(G, C[i - 1][L]));
            }
    		inc(f[i], 1ll * i * fac[i] % mod);
        }
        printf("%d
    ", g[n]);
    }
    
    int main() {
        cin >> n >> mod;
        init(); dp();
        return 0;
    }
    
  • 相关阅读:
    [树形dp] Luogu P4516 潜入行动
    [kruskal][Trie] Codeforces 888G Xor-MST
    [线性基] Luogu P4151 最大XOR和路径
    [线段树] Luogu P4560 砖墙
    [递归][重心] Luogu P4886 快递员
    [Trie][贪心][堆] LibreOJ #3048 异或粽子
    [长链剖分][优先队列] LibreOJ #3052 春节十二响
    [支配树] Bzoj P2815 灾难
    [长链剖分][线段树] Bzoj P1758 重建计划
    [dsu on tree] Codeforces 600E Lomsat gelral
  • 原文地址:https://www.cnblogs.com/reverymoon/p/10171657.html
Copyright © 2020-2023  润新知