首页 > 其他分享 >ICPC南京2024

ICPC南京2024

时间:2024-11-26 15:55:04浏览次数:6  
标签:ifac int siz ll 南京 ICPC 2024 ans mod

C. Topology

考虑没有限制怎么做,对于每个点分配 $$ (siz_x-1)! \prod \frac{1}{siz_v!}$$ 转化为子问题乘起来即可

如果 \(k\) 要放在 \(k\) ,我们从下往上放,对于 \(k\) 的子树先乘上\(\C_{n-i}^{siz_x}\),接着乘上子树对应的系数,使k的子树全都确定了

对于父节点 \(f\) 放在p 需要乘上\(C_{n-p-siz_k-1}^{siz_f - 1 -siz_k}\) 乘上其它对应结点的转移系数,重复这个操作即可

容易发现这个转移只需要知道 \(f,p,k\) 即可,我们不妨设 \(f_{ij}\) 表示第 i 个节点放在第j个位置转移时我们就可以乘上系数,直接转移是 \(n^3\) 的,用前缀和优化可以做到 \(n^2\)

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int mod = 998244353;
const int N = 5005;
int n ;
vector<int>gra[N];
int fa[N];
ll f[N][N],h[N];
ll fac[N],ifac[N];
ll g[N];
int siz[N];
ll ans[N];
ll C(int n,int m){
    if(n < 0 || m > n || m < 0) return 0;
    return fac[n] * ifac[m] % mod * ifac[n-m] %mod;
}

ll qpow(ll a,ll b=mod-2){
    ll ans = 1;
    for(;b;b>>=1,a=a*a%mod) if(b&1) ans = ans * a %mod;
    return ans;
}

void init(){
    fac[0] = 1;
    for(int i=1;i<N;i++) fac[i] = fac[i-1] * i % mod;
    ifac[5000] = qpow(fac[5000]);
    for(int i=5000-1;i>=0;i--) ifac[i] = ifac[i+1] * (i+1) %mod;
}


void dfs(int x){
    siz[x] = 1;
    h[x] = 1;
    for(auto v:gra[x]){
        dfs(v);
        siz[x] += siz[v];
        h[x] = h[x] * h[v] % mod;
        h[x] = h[x] * ifac[siz[v]] % mod; 
    }
    h[x] = h[x] * fac[siz[x]-1] % mod;
}

void solve(int x){
    if(x!=1){ 
        memset(g,0,sizeof g);
        int dad = fa[x];
        ll w1 = fac[siz[dad]-1-siz[x]];
        for(auto v:gra[dad]){
            if(v==x) continue;
            w1 = w1 * ifac[siz[v]] % mod;
            w1 = w1 * h[v] % mod ;
        }
        
        for(int j=1;j<=n;j++){
            ll w2 = C(n-j-siz[x],siz[dad] - siz[x] - 1);
            g[j] = f[dad][j] * w2 % mod;
            g[j] = (g[j] + g[j-1] ) %mod;
        }
        for(int j=1;j<=n;j++) f[x][j] = g[j-1] * w1 %mod; 
    }
    ans[x] = f[x][x] * C(n-x,siz[x]-1)  % mod;
    ans[x] = ans[x] * h[x] %mod;
    for(auto v:gra[x]) solve(v);
    
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    init();
    cin >> n;
    for(int i=2;i<=n;i++){
        cin >> fa[i];
        gra[fa[i]].emplace_back(i);
    }
    dfs(1);
    f[1][1] = 1;
    solve(1);
    for(int i=1;i<=n;i++) cout << ans[i] << " ";

    return 0;
}

标签:ifac,int,siz,ll,南京,ICPC,2024,ans,mod
From: https://www.cnblogs.com/dwdyy/p/18570354

相关文章