1. 程式人生 > 實用技巧 >#樹形dp#C 樹上排列

#樹形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);
}