nowcoder375C 小G砍树 换根DP

我们令 $f[i]$ 表示以 $i$ 为根的删除方案数.  

这里一定要注意一件事情:根据我们的定义,我们已经默认 $i$ 点为根的子树在删除时 $i$ 是最后删除的.   

然后按照换根 DP 的套路转移就行,但是转移的时候组合数一定要注意.   

#include <cstring> 
#include <cstdio> 
#include <algorithm> 
#define N 100007 
#define ll long long 
#define mod 998244353 
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;   
int qpow(int x,int y) 
{
    int tmp=1; 
    for(;y;y>>=1,x=(ll)x*x%mod) 
        if(y&1) tmp=(ll)tmp*x%mod; 
    return tmp; 
} 
int edges,n; 
int f[N],inv[N],fac[N],hd[N],to[N<<1],nex[N<<1],size[N],g[N];         
void add(int u,int v) 
{
    nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;  
}      
int C(int x,int y) 
{   
    return (ll)fac[x]*inv[y]%mod*inv[x-y]%mod;  
}
void dfs(int u,int ff) 
{
    size[u]=1,f[u]=1; 
    for(int i=hd[u];i;i=nex[i]) 
    {
        int v=to[i]; 
        if(v==ff) continue;  
        dfs(v,u);       
        f[u]=(ll)f[u]%mod*f[v]%mod*C(size[u]+size[v]-1,size[v])%mod;          
        size[u]+=size[v];   
    }  
} 
void dfs2(int u,int ff) 
{
    if(u==1) g[u]=f[u];    
    for(int i=hd[u];i;i=nex[i]) 
    {
        int v=to[i]; 
        if(v==ff) continue;            
        int remain=(ll)g[u]*qpow(f[v],mod-2)%mod*qpow(C(n-1,size[v]),mod-2)%mod;    
        g[v]=(ll)f[v]*remain%mod*C(n-1,n-size[v])%mod;       
        dfs2(v,u); 
    }    
}
int main() 
{
   // setIO("input"); 
    int i,j;  
    scanf("%d",&n); 
    for(i=1;i<n;++i) 
    {
        int x,y; 
        scanf("%d%d",&x,&y); 
        add(x,y),add(y,x);  
    }     
    fac[0]=inv[0]=1; 
    for(i=1;i<=n;++i) fac[i]=(ll)i*fac[i-1]%mod,inv[i]=qpow(fac[i],mod-2);   
    dfs(1,0);     
    dfs2(1,0); 
    int ans=0;       
    for(i=1;i<=n;++i) (ans+=g[i])%=mod; 
    printf("%d\n",ans); 
    return 0;
}

  

posted @ 2020-01-07 11:20  EM-LGH  阅读(149)  评论(0编辑  收藏  举报