用第二类斯特林公式代入 d i s t ( i , j ) k dist(i,j)^k dist(i,j)k(接下来用 d j d_j dj表示dis(i,j)): S ( i ) = ∑ j = 1 n d j k S(i) = \sum_{j = 1}^nd_j^k S(i)=j=1∑ndjk = ∑ j = 1 n ∑ t = 0 k S ( k , t ) [ d j ] t =\sum_{j = 1}^n\sum_{t=0}^kS(k,t)[d_j]_t =j=1∑nt=0∑kS(k,t)[dj]t = ∑ j = 1 n ∑ t = 0 k S ( k , t ) C ( d j , t ) ∗ t ! =\sum_{j = 1}^n\sum_{t=0}^kS(k,t)C(d_j,t)*t! =j=1∑nt=0∑kS(k,t)C(dj,t)∗t! = ∑ t = 0 k S ( k , t ) ∗ t ! ∑ j = 1 n C ( d j , t ) =\sum_{t=0}^kS(k,t)*t!\sum_{j = 1}^nC(d_j,t) =t=0∑kS(k,t)∗t!j=1∑nC(dj,t)
变成要快速求解
∑
j
=
1
n
C
(
d
j
,
t
)
\sum_{j = 1}^nC(d_j,t)
∑j=1nC(dj,t),接下来一步比较巧妙。
由于暴力是必定要T的,应该考虑是否能从其它点的答案转移以缩小时间复杂度。
对于二项式有个递推式: ∑ j = 1 n C ( d j , t ) = ∑ j = 1 n C ( d j − 1 , t ) + ∑ j = 1 n C ( d j − 1 , t − 1 ) \sum_{j = 1}^nC(d_j,t) = \sum_{j = 1}^nC(d_j - 1,t) + \sum_{j = 1}^nC(d_j - 1,t - 1) ∑j=1nC(dj,t)=∑j=1nC(dj−1,t)+∑j=1nC(dj−1,t−1)
满足
d
j
−
1
d_j - 1
dj−1的点一定是当前点的子结点或父节点,这意味着可以树形DP,用两次扫描换根来转移。
令
d
p
[
i
]
[
t
]
dp[i][t]
dp[i][t]表示结点
i
i
i 的
∑
j
=
1
n
C
(
d
j
,
t
)
\sum_{j = 1}^nC(d_j,t)
∑j=1nC(dj,t),
d
p
[
u
]
[
t
]
=
d
p
[
v
]
[
t
]
+
d
p
[
v
]
[
t
−
1
]
,
v
=
s
o
n
(
u
)
∣
f
a
t
h
e
r
(
u
)
dp[u][t] = dp[v][t] + dp[v][t-1],v =son(u) | father(u)
dp[u][t]=dp[v][t]+dp[v][t−1],v=son(u)∣father(u)
复杂度为
O
(
n
k
)
O(nk)
O(nk)
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e4 + 100;
const int mod = 10007;
int n,k;
vector<int> g[maxn];
int S[300][300],dp[maxn][300],pw[maxn];
int cur[300];
void dfs(int u,int f) {
dp[u][0] = 1;
for(auto it : g[u]) {
if(it == f) continue;
dfs(it,u);
dp[u][0] += dp[it][0];
dp[u][0] %= mod;
for(int j = 1; j <= k; j++) {
dp[u][j] += (dp[it][j - 1] + dp[it][j]) % mod;
dp[u][j] %= mod;
}
}
}
void dfs2(int u,int f) {
for(auto it : g[u]) {
if(it == f) continue;
cur[0] = (dp[u][0] - dp[it][0] + mod) % mod;
for(int j = 1; j <= k; j++) {
cur[j] = dp[u][j] - dp[it][j] - dp[it][j - 1];
cur[j] = (cur[j] + mod + mod) % mod;
}
dp[it][0] = (dp[it][0] + cur[0]) % mod;
for(int j = 1; j <= k; j++) {
dp[it][j] += (cur[j] + cur[j - 1]) % mod;
dp[it][j] %= mod;
}
dfs2(it,u);
}
}
int main() {
scanf("%d%d",&n,&k);
for(int i = 1; i < n; i++) {
int u,v;scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
pw[0] = S[0][0] = 1;
for(int i = 1; i <= 300; i++) {
pw[i] = pw[i - 1] * i % mod;
for(int j = 1; j <= i; j++)
S[i][j] = (S[i - 1][j - 1] + j * S[i - 1][j] % mod) % mod;
}
dfs(1,0);dfs2(1,0);
/*for(int i = 1; i <= n; i++)
for(int j = 1; j <= k; j++)
printf("**%d\n",dp[i][j]);*/
int ans = 0;
for(int i = 1; i <= n; i++) {
ans = 0;
for(int j = 0; j <= k; j++) {
ans += dp[i][j] * S[k][j] % mod * pw[j] % mod;
ans %= mod;
}
printf("%d\n",ans);
}
}