P13020 [GESP202506 八级] 遍历计数

GESP8 冲刺课堂页:先建模,再压缩状态,最后读代码。

一、先回答问题

结论

固定起点后,每个点只需要排列它的孩子访问顺序,最后可化成度数公式。

容易误入的路

枚举所有 DFS 顺序会指数爆炸,n 到 1e5 不可能。

二、核心观察

建模与压缩

以 s 为根时,根贡献 deg(s)!,其他点贡献 (deg(u)-1)!。

为什么不丢答案:DFS 在树上进入一个子树后必须完整返回,唯一自由度就是各孩子子树的访问顺序。

deg[u] 阶乘贡献 总公式

三、互动演示

步骤1
关键状态 A-
关键状态 B-
答案/目标-
复杂度看表
课堂动作手推

四、自己选答案

问题 1

根和非根贡献为什么不同?

问题 2

模数是多少?

五、手推结果

点类型孩子数贡献
根 sdeg(s)deg(s)!
非根 udeg(u)-1(deg(u)-1)!
总和所有起点2(n-1)*P

课堂要求:每题先说清对象、关系、保留的信息、压缩掉的信息,再写代码。

六、C++14 参考代码

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

typedef long long ll;
const int MOD = 1e9;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    if (!(cin >> n)) return 0;

    if (n == 1) {
        cout << 1 << endl;
        return 0;
    }

    vector<int> deg(n + 1, 0);
    for (int i = 0; i < n - 1; i++) {
        int u, v;
        cin >> u >> v;
        deg[u]++;
        deg[v]++;
    }

    // 预处理阶乘
    vector<ll> fact(n + 1);
    fact[0] = 1;
    for (int i = 1; i <= n; i++) {
        fact[i] = (fact[i - 1] * i) % MOD;
    }

    ll p = 1;
    for (int i = 1; i <= n; i++) {
        // 每个点贡献 (deg[i]-1)!
        if (deg[i] > 0) {
            p = (p * fact[deg[i] - 1]) % MOD;
        }
    }

    // 最终结果 = 2 * (n-1) * p
    ll ans = (2LL * (n - 1)) % MOD;
    ans = (ans * p) % MOD;

    cout << ans << endl;

    return 0;
}