• #树形dp#C 树上排列


    题目


    分析

    (dp[x][i])表示以(x)为根的子树中(x)的排名为(i)的方案数,
    然后枚举子节点转移即可,Talk is cheap,Show me the code


    代码

    #include <cstdio>
    #include <cctype>
    #define rr register
    using namespace std;
    const int N = 3011, mod = 998244353;
    struct node {
        int y, w, next;
    } e[N << 1];
    int siz[N], dp[N][N], f[N], as[N], fac[N], inv[N], n, et = 1, ans;
    inline signed iut() {
        rr int ans = 0;
        rr char c = getchar();
        while (!isdigit(c)) c = getchar();
        while (isdigit(c)) ans = (ans << 3) + (ans << 1) + (c ^ 48), c = getchar();
        return ans;
    }
    inline signed mo(int x, int y) { return x + y >= mod ? x + y - mod : x + y; }
    inline signed C(int n, int m) { return 1ll * fac[n] * inv[m] % mod * inv[n - m] % mod; }
    inline void dfs(int x, int fa) {
        siz[x] = dp[x][1] = 1;
        for (rr int i = as[x]; i; i = e[i].next)
            if (e[i].y != fa) {
                dfs(e[i].y, x);
                for (rr int j = 1; j <= siz[x]; ++j) f[j] = dp[x][j], dp[x][j] = 0;
                for (rr int j = 1; j <= siz[x]; ++j) {
                    rr int sum = 0;
                    if (e[i].w)
                        for (rr int o = siz[e[i].y]; ~o; --o)
                            dp[x][j + o] = mo(dp[x][j + o], 1ll * f[j] * C(j + o - 1, j - 1) % mod *
                                                                C(siz[x] + siz[e[i].y] - j - o, siz[x] - j) %
                                                                mod * sum % mod),
                                      sum = mo(sum, dp[e[i].y][o]);
                    else
                        for (rr int o = 0; o <= siz[e[i].y]; ++o)
                            sum = mo(sum, dp[e[i].y][o]),
                            dp[x][j + o] = mo(dp[x][j + o], 1ll * f[j] * C(j + o - 1, j - 1) % mod *
                                                                C(siz[x] + siz[e[i].y] - j - o, siz[x] - j) %
                                                                mod * sum % mod);
                }
                siz[x] += siz[e[i].y];
            }
    }
    signed main() {
        freopen("perm.in", "r", stdin);
        freopen("perm.out", "w", stdout);
        n = iut(), fac[0] = fac[1] = inv[0] = inv[1] = 1;
        for (rr int i = 2; i <= n; ++i) inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod;
        for (rr int i = 2; i <= n; ++i) fac[i] = 1ll * fac[i - 1] * i % mod;
        for (rr int i = 2; i <= n; ++i) inv[i] = 1ll * inv[i - 1] * inv[i] % mod;
        for (rr int i = 1; i < n; ++i) {
            rr int x = iut(), y = iut();
            e[++et] = (node){ y, 1, as[x] }, as[x] = et;
            e[++et] = (node){ x, 0, as[y] }, as[y] = et;
        }
        dfs(1, 0);
        for (rr int i = 1; i <= n; ++i) ans = mo(ans, dp[1][i]);
        return !printf("%d", ans);
    }
    
  • 相关阅读:
    java-集合框架-泛型2-泛型限定
    进程间通信
    多进程编程基础概念
    linux deb 打包流程
    linux RPM 打包流程
    Python 第一個程序
    从注册验证码入手,我保住了30%的流失用户
    为什么Web端登录需要验证码?
    网络验证码的进化:从简单图文到无感验证
    公开课 | 金融知识图谱的应用探索
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/14038010.html
走看看 - 开发者的网上家园