1. 程式人生 > 其它 >[國家集訓隊] Crash 的文明世界

[國家集訓隊] Crash 的文明世界

\(i\)點的指標值是樹上以\(i\)為起點的所有路徑長度的\(k\)次方的和

\(dist\)\(O(n)\)級別的,還是搞成下降冪來做.\(dist\)可以在\(log\)時間內求出。

\[\begin{aligned} &S(i)=\sum_{j=1}^ndist(i,j)^k \\=&\sum_{j=1}^{n}\sum_{x=0}^{k}S_k^xx!C_{dist(i,j)}^x \\=&\sum_{x=0}^kS_k^xx!\sum_{j=1}^nC_{dist(i,j)}^x \end{aligned} \]

後面那個和式可以用樹形\(dp\)求解,設\(f[x][i]\)

表示1為樹根時,以\(i\)為根的子樹內的\(j\)\(\sum_{j}C_{dist(i,j)}^x\),那麼根節點的答案是所有子結點答案中dist+1得到的答案,用楊輝三角公式可以進行轉移

\[f[x][i] = \sum_{i=fa(j)}(f[x][j]+f[x-1][j]) \]

這樣可以得到根節點的答案,通過換根dp(用以父節點為根的答案推算出以子結點為根的答案)可以得到所有點的答案。設\(g[x][i]\)表示點\(i\)為根的最終答案,\(tmp[x]\)表示當前點在以1為根的情況下,當前點子樹外的答案。那麼

\[g[x][i]=tmp[x]+tmp[x-1]+f[x][i] \]
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e4 + 7, md = 1e4 + 7;
#define ll long long
int rd() {
    int s = 0, f = 1; char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-') f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        s = s * 10 + c - '0';
        c = getchar();
    }
    return s * f;
}
int n, k;
vector<int> adj[maxn];
ll f[157][maxn], g[157][maxn], S[157][157], fac[maxn], tmp[157];
void dfs1(int u, int fa) {
    f[0][u] = 1;    //以u為根的子樹內, x=0的第二個和式的答案,C_0^0=1
    for (int i = 0; i < adj[u].size(); i++) {
        int v = adj[u][i];
        if (v == fa) continue;
        dfs1(v, u);
        f[0][u] = (f[0][u] + f[0][v]) % md;
        for (int j = 1; j <= k; j++) {
            f[j][u] = (f[j][u] + f[j-1][v] + f[j][v]) % md;
        }
    }
}
void dfs2(int u, int fa) {
    for (int i = 0; i <= k; i++) g[i][u] = f[i][u];
    if (u ^ fa) {
        tmp[0] = (g[0][fa] - f[0][u] + md) % md;
        for (int x = 1; x <= k; x++) {
            tmp[x] = (g[x][fa] - f[x][u] + md - f[x-1][u] + md) % md;
        }
        g[0][u] = (g[0][u] + tmp[0]) % md;
        for (int x = 1; x <= k; x++) {
            g[x][u] = (g[x][u] + tmp[x] + tmp[x-1]) % md;
        }
    }
    for (int i = 0; i < adj[u].size(); i++) {
        int v = adj[u][i];
        if (v ^ fa) {
            dfs2(v, u);
        }
    }
}
int main() {
    n = rd(), k = rd();
    for (int i = 1; i < n; i++) {
        int u = rd(), v = rd();
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    S[0][0] = fac[0] = 1;
    for (int i = 1; i <= k; i++) {
        fac[i] = fac[i-1] * i % md;
        for (int j = 1; j <= i; j++) {
            S[i][j] = (S[i-1][j-1] + 1ll * j * S[i-1][j]) % md;
        }
    }
    dfs1(1, 1);
    dfs2(1, 1);
    for (int i = 1; i <= n; i++) {
        int ans = 0;
        for (int x = 0; x <= k; x++) {
            ans += S[k][x] * fac[x] % md * g[x][i] % md;
            ans %= md;
        }
        printf("%d\n", ans);
    }
    return 0;
}