AT_abc160_f [ABC160F] Distributing Integers

AT_abc160_f [ABC160F] Distributing Integers

题面

求以每个点为根可以有多少种方案,使得对于每个点其父节点编号小于子节点

思路

换根都写题面上了,所以我们考虑如何以一点为根 dp。

容易想到,这是个很经典的 dp。也就是设 \(dp_{u}\) 表示 \(u\) 的子树内的方案数。考虑如何合并,假设现在有 \(sm_{u}\) 个点,然后又一个儿子有 \(sm_{v}\),那么就相当于将 \(sm_{v}\) 个不区分小球放入 \(sm_{u}\) 个可区分盒子里,然后这不可区分球再有 \(dp_{v}\) 个排序方案。所以最终转移就是:

\[dp_u(^{sm_{u}+sm_{v}-1}_{\ \ \ \ \ sm_{u}-1})dp_v \to dp_u \]

换根就是模板的换根,也就是将父亲中关于自己子树的贡献剔除,如将 \(sm_{u}\) 减少和 \(dp_{u}\) 处以对应贡献,然后把父亲当做儿子去转移即可。

代码

#include <bits/stdc++.h>
using namespace std;
// typedef long long ll;
#define int long long
typedef long double ld;
#define freop(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout);
#define endl '\n'
#define inf 0x7f7f7f7f
#define lb(x) ((x)&-(x))
#define pii pair<int,int>
#define fir first
#define sec second
#define mkp(a,b) make_pair(a,b)
const int N=2e5+10,mod=1e9+7;
int n,sm[N],fac[N]={1},inv[N],dp[N];
vector<int> g[N];

inline int C(int n,int m){return fac[n]*inv[m]%mod*inv[n-m]%mod;}
inline int ksm(int a,int b=mod-2){
    int c=1;
    while(b){
        if(b&1) c=c*a%mod;
        b>>=1,a=a*a%mod;
    }
    return c;
}
void dfs1(int u,int fa){
    dp[u]=sm[u]=1;
    for(int v:g[u]) if(v^fa)
        dfs1(v,u),
        dp[u]=dp[u]*C(sm[u]+sm[v]-1,sm[u]-1)%mod*dp[v]%mod,
        sm[u]+=sm[v];
    
}
void dfs2(int u,int fa){
    int tsm=sm[fa]-sm[u],tdp=dp[fa]*ksm(dp[u])%mod*ksm(C(tsm+sm[u]-1,tsm-1))%mod;
    // cerr << u << ':' << dp[u] << ' ' << sm[u] << "  " << fa << ':' << tdp << ' ' << tsm << endl;
    dp[u]=dp[u]*C(sm[u]+tsm-1,sm[u]-1)%mod*tdp%mod,sm[u]=sm[fa];
    for(int v:g[u]) if(v^fa) dfs2(v,u);
}

signed main(){
    cin.tie(0)->ios::sync_with_stdio(false);
    cout.tie(0);
    for(int i = 1;i<N;++i) fac[i]=fac[i-1]*i%mod;
    inv[N-1]=758835755;
    for(int i = N-2;~i;--i) inv[i]=inv[i+1]*(i+1)%mod;
    // freop();
//↑以上为初始化↑
//------------------------------
    cin >> n;
    for(int i = 1,u,v;i<n;++i)
        cin >> u >> v,
        g[u].push_back(v),
        g[v].push_back(u);
    dfs1(1,0);
    for(int u:g[1]) dfs2(u,1);
    for(int i = 1;i<=n;++i)
        cout << dp[i] << endl;
    return 0;
}
posted @ 2026-10-21 21:00  elon_giao  阅读(3)  评论(0)    收藏  举报