AT_tdpc_tree 木

题目描述:

给定一棵大小为 n 的树,用另外 n 个点加边构造出这棵树,要求构造时所被边连到的点联通,求有多少连边顺序。

数据范围:

1n1000

思路:

首先我们发现,因为题目要求连边后一定是一个连通块,所以考虑以哪一个点作为起点,然后向下连边。

所以我们得到一个初步的思路:枚举点 u 求出以 u 为根的连边方案数

然后我们就思考一下怎么处理这个问题?

考虑树形 Dp:令 fu 表示以 u 为根的子树连边的方案数是多少。

假设我们已经算出了 fv,考虑怎么将 fv 合并到 fu 中。

u 的儿子之间的连边其实是独立的,也就是说如果我们确定了 v 中的连边顺序,则只要这个连边的相对顺序不变,就可以成为一个合法的方案。

所以假设枚举到了 v,并且当前这些子树中的边的数量为 szu,子树 v 中的边的数量为 szv

则方案数就是 (szuszv),即从 szu 条边中,选 szv 个位置放 v 子树内填的边。

所以可以得出 fufv×(szuszv)

注意的是,这里的 szu 都是指的是边数,而不是点数。

#include<bits/stdc++.h> using namespace std; #define int long long const int maxn=1005; const int mod=1e9+7; int fac[maxn],inv[maxn]; int qp(int x,int k){ int res=1; while(k){ if(k&1)res=res*x%mod; x=x*x%mod; k>>=1; } return res; } void init(){ int N=maxn-5; fac[0]=1; for(int i=1;i<=N+1;i++)fac[i]=fac[i-1]*i%mod; inv[N+1]=qp(fac[N+1],mod-2); for(int i=N;i>=0;i--)inv[i]=inv[i+1]*(i+1)%mod; return ; } int C(int n,int m){ if(n<m||m<0)return 1; return fac[n]*inv[m]%mod*inv[n-m]%mod; } int n; vector<int>G[maxn]; int sz[maxn],dep[maxn],f[maxn]; void dfs(int u,int fa){ f[u]=1; sz[u]=0; for(int v:G[u]){ if(v==fa)continue; dfs(v,u); sz[u]+=sz[v]; f[u]=f[u]*f[v]%mod*C(sz[u],sz[v])%mod; } sz[u]++; return ; } signed main(){ 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); } init(); int ans=0; for(int i=1;i<=n;i++){ dfs(i,0); ans=(ans+f[i])%mod; } cout<<ans*qp(2,mod-2)%mod<<endl; return 0; }

__EOF__

本文作者Candycar
本文链接https://www.cnblogs.com/Candycar/p/17833460.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Candycar  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
点击右上角即可分享
微信分享提示