Atcoder ABC 160 F - Distributing Integers 换根dp+概率
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\n",dp[i]);
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· 本地部署DeepSeek后,没有好看的交互界面怎么行!
· 趁着过年的时候手搓了一个低代码框架
· 推荐一个DeepSeek 大模型的免费 API 项目!兼容OpenAI接口!