[國家集訓隊] Crash 的文明世界
阿新 • • 發佈:2021-07-21
\(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]\)
這樣可以得到根節點的答案,通過換根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; }