【atc abc160F】F - Distributing Integers(树的拓扑序计数)
作者:互联网
题意:
求以每个点为根节点的树的拓扑序计数。
思路:
是一个挺经典的问题。
我们考虑自下而上的树形\(dp\):假设我们当前点在\(u\),我们已经求出来了\(dp[v],v\in sons_u\)。
现在要求\(u\)的方案数,我们考虑在\(u\)放上\(1\),然后剩下\(sz[u]-1\)个数生成一个排列依次给每个结点赋值。之后类似于一个可重集的排列问题,对于每个结点,我们要除以\(sz[v]!\),就相当于我们从\(sz[u]-1\)个数中拿出来一些数给\(v\)这颗子树赋值,不考虑顺序的情况下,这些数不同的方案数。接下来就考虑上顺序,乘以一个\(dp[v]\)就行。所以总的方案数为:
\[(sz[u] - 1)!\cdot \prod\frac{dp[i]}{sz[i]!},u\in father(i) \]
当然,还有更加简单的公式,我们不用考虑\(dp\),因为我们发现首位固定最小的排列数为\((n-1)!\)。那么对于以\(u\)为根节点的子树答案为:
\[sz[u]!\prod\frac{1}{sz[i]},u\in father(i) \]
这两个式子是等价的,我们可以直接归纳证明。
这样就求出来了以一个点作为根节点的情况,求所有点作为根结点的情况直接换根跑一下就行。
细节见代码:
/*
* Author: heyuhhh
* Created Time: 2020/5/16 17:42:54
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << std::endl; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A>
void err(const T <t> &arg, const A&... args) {
for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
#define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 2e5 + 5, MOD = 1e9 + 7;
int qpow(ll a, ll b) {
ll res = 1;
while (b) {
if (b & 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
int n;
vector <int> G[N];
int sz[N], f[N];
void dfs(int u, int fa) {
sz[u] = 1;
for (auto v : G[u]) if (v != fa) {
dfs(v, u);
sz[u] += sz[v];
}
}
void dfs2(int u, int fa) {
for (auto v : G[u]) if (v != fa) {
f[v] = 1ll * f[u] * sz[v] % MOD * qpow(n - sz[v], MOD - 2) % MOD;
dfs2(v, u);
}
}
void run() {
cin >> n;
for (int i = 1; i < n; i++) {
int u, v; cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1, 0);
f[1] = 1;
for (int i = 1; i <= n; i++) {
f[1] = 1ll * f[1] * i % MOD;
}
for (int i = 1; i <= n; i++) {
f[1] = 1ll * f[1] * qpow(sz[i], MOD - 2) % MOD;
}
dfs2(1, 0);
for (int i = 1; i <= n; i++) {
cout << f[i] << '\n';
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
run();
return 0;
}
标签:Integers,atc,sz,int,void,MOD,Distributing,include,define 来源: https://www.cnblogs.com/heyuhhh/p/12912044.html