Atcoder ABC 160 F

Atcoder ABC 160 F - Distributing Integers

题意

给一棵树,从一个点出发每次可以向相邻的点传递一次,第i次传递到的点编号为i,问分别从1--n点出发编号有多少种

题解

首先1--n点出发分别算出值可以看出是个换根dp,那么最重要的是怎么求出指定一个根它的值。这题其实就是求一个拓扑序,对于一个n个点的数来说,排列一共有(n!)个那么在这所有排列中,第一个点一定标号为1,也就是说(n!)个点中。(1/n)的可能性达成上述目标,也就是说有((n-1)!)个序列是满足条件的,那对于它的子节点如果算呢,如果一个子节点的子树大小为sz,那么有(1/sz)的可能性满足子树的根在第一个,因为概率是互相独立的,所以对于一个点来说,合法的序列为(frac{n!}{Sigma_{1}^nsz[i]}),而题目要求1-n的,换一下根即可
逆元,阶乘逆元均可打表

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define F first
#define S second
#define mkp make_pair
#define pii pair<int,int>
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=2e5+5;
const int mod=1e9+7;
int fac[maxn],inv[maxn],dp[maxn],sz[maxn];
int n;
vector<int>v[maxn];
ll mul(ll a,ll b){
	return (a*b)%mod;
}
void init(int n){
	fac[1]=1;
	fac[0]=1;
	for(int i=2;i<=n;i++){
		fac[i]=mul(fac[i-1],i);
	}
	inv[1] = 1;
	for(int i = 2; i <=n; ++ i)
    inv[i] = mul((mod - mod / i) , inv[mod % i] );
}
void dfs(int x,int fa){
	sz[x]=1;
	for(auto y:v[x]){
		if(y==fa)continue;
		dfs(y,x);
		sz[x]+=sz[y];
	}
}
void reroot(int x,int fa){
	dp[x]=mul(mul(dp[fa],sz[x]),inv[(n-sz[x])]);
	for(auto p:v[x]){
		if(p==fa)continue;
		reroot(p,x);
	}
}
int main(){
	
	scanf("%d",&n);
	init(n);
	for(int i=1;i<n;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		v[x].pb(y);
		v[y].pb(x);
	}
	dfs(1,-1);
	dp[1]=fac[n];
	for(int i=1;i<=n;i++){
		dp[1]=mul(dp[1],inv[sz[i]]);
	}

	for(auto p:v[1]){
		reroot(p,1);
	}
	for(int i=1;i<=n;i++)printf("%d
",dp[i]);
	return 0;
}

原文地址:https://www.cnblogs.com/ttttttttrx/p/12642629.html