題解 Crash 的文明世界
阿新 • • 發佈:2020-07-27
題目大意
給出一個\(n\)個點的樹,和常數\(k\),對於\(\forall i\in[1,n]\),求出:
\[\sum_{j=1}^{n} \text{dist}(i,j)^k \]
\(n\le 5\times 10^4,k\le 150\)
思路
真的很妙,一開始完全沒有思路,看了\(\texttt{y2823774827y}\)的題解之後瞬間懂了。
我們考慮對於\(i\)如何計算答案,我們發現這個指數非常不好看,於是我們可以使用第二類斯特林數展開,就跟組合數問題差不多的,變為:
\[\sum_{j=1}^{n}\sum_{d=0}^{\text{dist}(i,j)}\binom{\text{dist}(i,j)}{d}\begin{Bmatrix}k\\d\end{Bmatrix}d! \]
交換求和順序可以得到:
\[=\sum_{d=0}^{\min(n,k)}\begin{Bmatrix}k\\d\end{Bmatrix}d!\sum_{j=1}^{n}\binom{\text{dist}(i,j)}{d} \]
於是,我們的問題就是如何快速求出後面那個\(\sum\)。我們想到這個東西可以拆成:
\[\binom{\text{dist}(i,j)}{d}=\binom{\text{dist}(i,j)-1}{d}+\binom{\text{dist}(i,j)-1}{d-1} \]
於是,我們用換根\(dp\)解決這個問題了。具體見程式碼。
\(\texttt{Code}\)
#include <bits/stdc++.h> using namespace std; #define Int register int #define MAXN 50005 #define mod 10007 #define MAXM 155 int qkpow (int a,int b){ int res = 1;for (;b;b >>= 1,a = 1ll * a * a % mod) if (b & 1) res = 1ll * res * a % mod; return res; } int mul (int a,int b){return 1ll * a * b % mod;} int dec (int a,int b){return a >= b ? a - b : a + mod - b;} int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;} struct edge{ int v,nxt; }e[MAXN << 1]; int top = 1,head[MAXN]; void Add_Edge (int u,int v){ e[++ top] = edge {v,head[u]},head[u] = top; e[++ top] = edge {u,head[v]},head[v] = top; } int n,k,S[MAXM][MAXM],fac[MAXM],dp1[MAXN][MAXM],dp2[MAXN][MAXM],tmp[MAXM]; //dp1[u][k]表示的是\sum_{j在i的子樹內(包括i)} \binom{dist(i,j)}{k} //dp2[u][k]表示的是\sum_{j=1}^{n} \binom{dist(i,j)}{k} void dfs1 (int u,int fa){ dp1[u][0] = 1; for (Int i = head[u];i;i = e[i].nxt){ int v = e[i].v; if (v == fa) continue; dfs1 (v,u); for (Int j = 1;j <= k;++ j) dp1[u][j] = add (dp1[u][j],add (dp1[v][j],dp1[v][j - 1])); dp1[u][0] = add (dp1[u][0],dp1[v][0]); } } void dfs2 (int u,int fa){//換根dp for (Int i = 0;i <= k;++ i) dp2[u][i] = dp1[u][i]; if (fa){ for (Int i = 1;i <= k;++ i) tmp[i] = dec (dp2[fa][i],add (dp1[u][i],dp1[u][i - 1])); tmp[0] = dec (dp2[fa][0],dp1[u][0]); for (Int i = 1;i <= k;++ i) dp2[u][i] = add (dp2[u][i],add (tmp[i],tmp[i - 1])); dp2[u][0] = add (dp2[u][0],tmp[0]); } for (Int i = head[u];i;i = e[i].nxt){ int v = e[i].v; if (v == fa) continue; dfs2 (v,u); } } template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;} template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);} template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');} signed main(){ read (n,k),S[0][0] = fac[0] = 1; for (Int i = 1;i <= k;fac[i] = mul (i,fac[i - 1]),++ i) for (Int j = 1;j <= i;++ j) S[i][j] = add (S[i - 1][j - 1],mul (j,S[i - 1][j])); for (Int i = 2,u,v;i <= n;++ i) read (u,v),Add_Edge (u,v); dfs1 (1,0),dfs2 (1,0); for (Int i = 1;i <= n;++ i){ int sum = 0; for (Int j = 0;j <= k;++ j) sum = add (sum,mul (fac[j],mul (S[k][j],dp2[i][j]))); write (sum),putchar ('\n'); } return 0; }