题解:P13020 [GESP202506 八级] 遍历计数

首先我们有一个很显然的树形 DP。

f[u] 为根节点为 u 的子树内的方案数,然后更新就是对于子树求乘积,并乘上子节点数的阶乘。

然后我们可以考虑换根,这时候有一个很难搞的问题,就是我们换根是需要除法的,但是模数不是质数,当然,我们可以维护一个前后缀的答案,再把阶乘单独拿出来之类的,也可以实现,事实上,这是我赛时做法,但这样太麻烦了。

我们可以考虑固定某一个点时根时,其他的点对于答案的贡献是什么。

我们发现这些东西都是些累乘,并没有加和。所以,在确定了根节点时,这其实是每一个点都有一部分贡献,而这部分贡献就是子节点数的阶乘。

只有根节点会有一些不同,他不再是度数减一的阶乘,而是度数的阶乘。

说到这里,答案就很好算了。

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 5;
const int Mod = 1e9;

int d[N];
int pre[N], suf[N];
int fac[N];

int main() {
    int n;
    cin >> n;
    for(int i = 1, u, v;i < n;i ++ ) {
        cin >> u >> v;
        d[u] ++ ;
        d[v] ++ ;
    }
    fac[0] = 1;
    for(int i = 1;i <= n;i ++ ) {
        fac[i] = fac[i - 1] * i % Mod;
    }
    pre[0] = 1;
    for(int i = 1;i <= n;i ++ ) {
        pre[i] = 1ll * pre[i - 1] * fac[d[i] - 1] % Mod;
    }
    suf[n + 1] = 1;
    for(int i = n;i >= 1;i -- ) {
        suf[i] = 1ll * suf[i + 1] * fac[d[i] - 1] % Mod;
    }
    long long ans = 0;
    for(int i = 1;i <= n;i ++ ) {
        ans += 1ll * pre[i - 1] * suf[i + 1] % Mod * fac[d[i]] % Mod;
    }
    cout << ans;
    return 0;
}
posted @ 2025-09-16 19:43  yanbinmu  阅读(10)  评论(0)    收藏  举报