Typical DP Contest N - 木
問題
n頂点からなる木が与えられる。
この木を、辺を一本ずつ書いていく。書いている途中の辺は全て連結であるようにしたい。
辺を書く順番は何通りあるかmod 10^9 + 7で求めよ。
制約条件
n≦1000
方針
木の根rを固定して考える。
dp[i]を、頂点i以下の部分木で、iとiの親の辺が既に書いてあるときの、
部分木の書き方の場合の数とする。
iとiの親の辺が既にあるので、
iからは子を順番に書いていくしかない。子がp, qのときは、
dp[i] = C(sz(p) + sz(q), sz(p)) * dp[p] * dp[q]という感じになる。
三つ以上のときも同様に辺の順番に自由度がある。
これで、dp[r]はrから辺を書き始めたときの総数になるので、
rを全ての頂点について動かして和を取ればよい。
ソースコード
pair<ll, int> rec(int c, int p){ ll res = 1, sz = 0; rep(i, e[c].size()) if(e[c][i] != p){ pi x = rec(e[c][i], c); res = res * x.first % mod; res = res * inv(fact[x.second]) % mod; sz += x.second; } res = res * fact[sz] % mod; return mp(res, sz + 1); } ll calc(int root){ return rec(root, root).first; } int main(){ fact[0] = 1; rep(i, 1000) fact[i+1] = fact[i] * (i+1ll) % mod; cin >> n; e.resize(n); rep(i, n - 1){ int a, b; cin >> a >> b; a--; b--; e[a].pb(b); e[b].pb(a); } ll ans = 0; rep(i, n) ans += calc(i); cout << ans % mod * inv(2) % mod << endl; return 0; }
残り、G, Sの解説書けばコンプリート。