https://atcoder.jp/contests/abc160

F - Distributing Integers

 

题意:给定一棵树,选定一个点作为初始点,赋值 11,对于 22nn,可以赋值给任意与已赋值点相邻的点,问以每个点作为初始点时各有多少种赋值方式。

数论+树形dp+换根dp

先考虑固定根的情况下求赋值方式数。

uu 为根的子树的赋值结果是u的子孙节点的排列,假设 uu 共有 CC 个子孙节点,则第一个子节点的子树的赋值结果可以选 cc 个位置中的几个放入,其内部的顺序就是该子树的赋值结果,可以递归得到。而 uu 的所有子节点都选好位置后,就构成了 uu 的赋值结果。

所以这是一个可重排列的问题,从 CC 个位置中选择 c1c_1 个位置放第一个子节点, c2c_2 个位置放第二个子节点,······,而对于各个子节点内部是怎样的顺序,我们并不关心,所以就是 C!c1!c2!ck!\frac{C!}{c_1!\cdot c_2!\cdots c_k!}。再乘以各个子节点的递归值,就是u的值。

再考虑换根。

假设 uu 为根,现在要求 ans[v]ans[v],则要把 uu 变成 vv 的子节点,乘到 vv 的答案里去,但是由于之前 vvuu 的子节点,所以要先把 vvuu 的子节点中去掉,就是乘以 (Ccv)!cv!C!dp[v]\frac{(C-c_v)!\cdot c_v!}{C!\cdot dp[v]},也就是 1Comb(C,Cv)dp[v]\frac{1}{Comb(C,C_v)\cdot dp[v]},之后再把 vv 视为根,一次更新 vv 的子节点即可,注意由于始终把 uu 作为根,所以子节点数始终是 n1n-1

或者考虑 Comb(c1,c1)dp[1]Comb(c1+c2,c2)dp[2]Comb(c1+c2+ck,ck)dp[k]Comb(c_1,c_1)dp[1]\cdot Comb(c_1+c_2,c_2)dp[2]\cdots Comb(c_1+c_2+\cdots c_k,c_k)dp[k],与 C!c1!c2!ck!dp[1]dp[2]dp[k]\frac{C!}{c_1!\cdot c_2!\cdots c_k!}dp[1]dp[2]\cdots dp[k] 也是一样的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e5 + 10;
const int INF = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
int n;
ll fac[N], inv[N];
ll power(ll a, ll x) {
ll ans = 1;
while (x) {
if (x & 1) ans = (ans * a) % mod;
a = (a * a) % mod;
x >>= 1;
}
return ans;
}
void init() {
fac[0] = 1;
for (int i = 1; i < N; i++) {
fac[i] = fac[i - 1] * i %mod;
}
inv[N - 1] = power(fac[N - 1], mod - 2);
for (int i = N - 2; i >= 0; i--) {
inv[i] = inv[i + 1] * (i + 1) % mod;
}
}
ll C(ll n, ll k) {
return fac[n] * inv[k] % mod*inv[n - k] % mod;
}
vector<int>G[N];
ll dp[N], ans[N], cnt[N];
void dfs1(int u, int _fa) {
cnt[u] = dp[u] = 1;
for (int v : G[u]) {
if (v == _fa)continue;
dfs1(v, u);
cnt[u] += cnt[v];
dp[u] = dp[u] * dp[v] % mod * C(cnt[u] - 1, cnt[v]) % mod;
}
}
void dfs2(int u, int _fa) {
for (int v : G[u]) {
if (v == _fa)continue;
ans[v] = ans[u] * power(dp[v] * C(n - 1, cnt[v]) % mod, mod - 2) % mod;
ans[v] = ans[v] * dp[v] % mod*C(n - 1, n - cnt[v]) % mod;
dfs2(v, u);
}
}
int main() {
init();
scanf("%d", &n);
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);
}
dfs1(1, 0);
ans[1] = dp[1];
dfs2(1, 0);
for (int i = 1; i <= n; i++)printf("%lld\n", ans[i]);
return 0;
}