【JZOJ 省选模拟】树与路径(path)

题目

Description
在这里插入图片描述

Input
在这里插入图片描述

Output
在这里插入图片描述

Sample Input
样例 1 输入:
6
1 2
2 3
1 4
2 5
1 6
样例 2 输入:
12
6 1
6 7
1 12
6 3
7 11
12 5
1 8
12 2
1 10
1 4
3 9

Sample Output
样例 1 输出:
0 0 9 6 1
样例 2 输出:
0 0 0 0 135 450 579 364 117 18 1

Data Constraint
在这里插入图片描述

思路

考虑把每个点相连的边配对,每配一次就代表把这两段拼起来

n条边配m对的方案为C(n,2)C(n-2,2)…*C(n-2(m-1),2)/m!

按哈夫曼树(合并果子)顺序合并多项式(分治FFT),时间O(n log^2 n)

代码

#include<bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define ll long long
#define mod 998244353
#define G 3
using namespace std;
const int M=2e5+77;
struct yjy
{
    int x,y;
    friend bool operator < (yjy a,yjy b) {return a.y>b.y;}
};
ll a[M],b[M],A[M],fac[M],Fac[M],w[M],s;
int d[M],n,i,j,k,l,N,len,x,y,n1,n2;
vector<int> f[M];
priority_queue<yjy> heap;

ll C(int n,int m)
{
    return fac[n]*Fac[m]%mod*Fac[n-m]%mod;
}

ll power(ll a,int b)
{
    ll ans=1;
    
    while (b)
    {
        if (b&1)
        ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    
    return ans;
}

void dft(ll *a,int yjy)
{
    int i,j,k,l,s1=2,s2=1,S=N;
    ll w,W,u,v;
    
    fo(i,0,N-1)
    {
        j=i;k=0;
        fo(l,1,len)
        k=k*2+(j&1),j>>=1;
        
        A[k]=a[i];
    }
    memcpy(a,A,8*N);
    
    fo(i,1,len)
    {
        if (yjy==1)
        w=power(G,(mod-1)/s1);
        else
        w=power(G,(mod-1)-(mod-1)/s1);
        S>>=1;
        
        fo(j,0,S-1)
        {
            W=1;
            
            fo(k,0,s2-1)
            {
                u=a[j*s1+k];
                v=a[j*s1+k+s2]*W;
                
                a[j*s1+k]=(u+v)%mod;
                a[j*s1+k+s2]=(u-v)%mod;
                W=W*w%mod;
            }
        }
        
        s1<<=1;s2<<=1;
    }
}

int main()
{
    freopen("path.in","r",stdin);
    freopen("path.out","w",stdout);
    
    scanf("%d",&n);
    w[1]=fac[0]=fac[1]=Fac[0]=Fac[1]=1;
    fo(i,2,n)
    {
        w[i]=mod-w[mod%i]*(mod/i)%mod;
        
        fac[i]=fac[i-1]*i%mod;
        Fac[i]=Fac[i-1]*w[i]%mod;
        
        scanf("%d%d",&j,&k);
        ++d[j];++d[k];
    }
    fo(i,1,n)
    {
        heap.push({i,d[i]/2});
        f[i].push_back(1);
        s=1;
        fo(j,1,d[i]/2)
        {
            s=s*C(d[i]-(j-1)*2,2)%mod;
            f[i].push_back(s*Fac[j]%mod);
        }
        d[i]/=2;
    }
    
    fo(i,1,n-1)
    {
        x=(heap.top()).x;heap.pop();
        y=(heap.top()).x;heap.pop();
        
        n1=d[x]; fo(j,0,n1) a[j]=f[x][j]; f[x].clear();
        n2=d[y]; fo(j,0,n2) b[j]=f[y][j]; f[y].clear();
        
        len=ceil(log2(n1+n2+1));N=power(2,len);
        fo(j,n1+1,N-1) a[j]=0;
        fo(j,n2+1,N-1) b[j]=0;
        
        dft(a,1);
        dft(b,1);
        fo(j,0,N-1) a[j]=a[j]*b[j]%mod;
        dft(a,-1);
        
        N=power(N,mod-2);
        d[x]+=d[y];
        fo(j,0,d[x])
        f[x].push_back(a[j]*N%mod);
        
        heap.push({x,d[x]});
    }
    
    x=(heap.top()).x;
    fo(i,1,n-1)
    if (i<(n-1)-d[x])
    printf("0 ");
    else
    printf("%d ",(f[x][(n-1)-i]+mod)%mod);
    printf("\n");

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值