【组合计数】树上拓扑序 UVA11174 Stand in a Line
板子题:
https://www.luogu.com.cn/problem/UVA11174
分析
整个图形成了一片森林,我们记一棵树(根节点记为 )的排序方案数为 。
我们记 以下的子节点(即它们的父节点为 )为 。
方便起见,记 为以其为根的子树大小。
我们看看如何选取可以构成一个合法的序列:
首先序列第一个元素必然是根 。
对子树内部的点进行排序,由乘法原理知一定有 种方案。
假设每棵子树内部的点已经排好一定的顺序,那么每个子树内的点都可以看成是相同的元素,因此排列计数的方案数为 。
因此由乘法原理,总共的方案数为:
假设 有 个子节点(记为 ),类似地有:
对所有节点求积,即得
其中 代表除了根以外的所有节点。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
using ll=long long;
const int N=4e4+5, M=N<<1, mod=1e9+7;
int n, m;
struct node{
int to, next;
}e[M];
int h[N], tot;
void add(int u, int v){
e[tot].to=v, e[tot].next=h[u], h[u]=tot++;
}
bool vis[N];
int sz[N];
void dfs(int u, int fa){
sz[u]=1;
for(int i=h[u]; ~i; i=e[i].next){
int go=e[i].to;
if(go==fa) continue;
dfs(go, u);
sz[u]+=sz[go];
}
}
ll fpow(ll x,ll p)
{
ll res=1;
for(;p;p>>=1,x=x*x%mod)
if(p&1)res=res*x%mod;
return res%mod;
}
ll inv(ll x){
return fpow(x,mod-2)%mod;
}
ll fac[N];
void init(){
fac[0]=1;
for(int i=1; i<N; i++) fac[i]=fac[i-1]*i%mod;
}
ll C(ll a, ll b){
return fac[a]*inv(fac[b])%mod*inv(fac[a-b])%mod;
}
signed main(){
init();
int T; cin>>T;
while(T--){
memset(h, -1, sizeof h), tot=0;
memset(vis, 0, sizeof vis);
cin>>n>>m;
for(int i=0; i<m; i++){
int u, fa; cin>>u>>fa;
add(fa, u), add(u, fa);
vis[u]=true;
}
for(int i=1; i<=n; i++) if(!vis[i]) add(i, 0), add(0, i);
dfs(0, -1);
int t=1;
for(int i=1; i<=n; i++) t=t*inv(sz[i])%mod;
cout<<fac[sz[0]-1]*t%mod<<endl;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】