[BZOJ3684]大朋友和多叉树

版权声明:既然是蒟蒻写的文,那么各位大爷就将就着看吧~ https://blog.csdn.net/alan_cty/article/details/81914993

Description

我们的大朋友很喜欢计算机科学,而且尤其喜欢多叉树。对于一棵带有正整数点权的有根多叉树,如果它满足这样的性质,我们的大朋友就会将其称作神犇的:点权为1的结点是叶子结点;对于任一点权大于1的结点u,u的孩子数目deg[u]属于集合D,且u的点权等于这些孩子结点的点权之和。
给出一个整数s,你能求出根节点权值为s的神犇多叉树的个数吗?请参照样例以更好的理解什么样的两棵多叉树会被视为不同的。
我们只需要知道答案关于950009857(453*2^21+1,一个质数)取模后的值。
m,s<=100000

Solution

样例告诉我们儿子是有顺序的
设F(x)为答案的生成函数,那么我们有

F ( x ) = i S F i ( x ) + x

考虑写成复合逆的形式,
F ( x ) i S F i ( x ) = x

把F(x)用x替换,设左边的生成函数为G(x),那么F(x)和G(x)互为复合逆
拉格朗日反演:
[ x n ] F ( x ) = 1 n [ x n 1 ] ( x G ( x ) ) n

发现右边x/G(x)的常数项是1,于是我们可以用求ln再求exp的方式来做快速幂
然后就写多项式全家桶喽

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;

typedef long long ll;

const int N=4e5+5,Mo=950009857;

int pwr(int x,int y) {
    int z=1;
    for(;y;y>>=1,x=(ll)x*x%Mo)
        if (y&1) z=(ll)z*x%Mo;
    return z;
}

ll t[N],W[N];

void DFT(ll *a,int len,int flag) {
    int lg=0;for(;(1<<lg)<len;lg++);
    W[0]=1;W[1]=pwr(7,(Mo-1)/len);
    fo(i,2,len) W[i]=W[i-1]*W[1]%Mo;
    for(int i=0;i<len;i++) {
        int p=0;
        for(int j=i,k=0;k<lg;k++,j>>=1) p=(p<<1)+(j&1);
        t[p]=a[i];
    }
    for(int m=2;m<=len;m<<=1) {
        int half=m/2,times=len/m;
        for(int i=0;i<half;i++) {
            ll w=(flag>0)?W[i*times]:W[len-i*times];
            for(int j=i;j<len;j+=m) {
                ll u=t[j],v=t[j+half]*w;
                t[j]=(u+v)%Mo;t[j+half]=(u-v)%Mo;
            }
        }
    }
    for(int i=0;i<len;i++) a[i]=t[i];
    if (flag==-1) {
        int inv=pwr(len,Mo-2);
        for(int i=0;i<len;i++) a[i]=a[i]*inv%Mo;
    }
}

ll c[N];

void get_Inv(ll *a,ll *b,int n) {
    if (n==1) {b[0]=pwr(a[0],Mo-2);return;}
    get_Inv(a,b,n>>1);
    int len=n<<1;
    fo(i,0,n-1) c[i]=a[i];fo(i,n,len-1) c[i]=0;
    fo(i,(n>>1),len-1) b[i]=0;
    DFT(c,len,1);DFT(b,len,1);
    fo(i,0,len-1) b[i]=(2*b[i]-b[i]*b[i]%Mo*c[i])%Mo;
    DFT(b,len,-1);
    fo(i,n,len-1) b[i]=0;
}

ll f[N],g[N];

void get_ln(ll *a,ll *b,int n) {
    fo(i,0,n-2) f[i]=a[i+1]*(i+1)%Mo;f[n-1]=0;
    get_Inv(a,g,n);
    int len=n<<1;
    fo(i,n,len-1) f[i]=g[i]=0;
    DFT(f,len,1);DFT(g,len,1);
    fo(i,0,len-1) f[i]=f[i]*g[i]%Mo;
    DFT(f,len,-1);
    fo(i,1,n-1) b[i]=f[i-1]*pwr(i,Mo-2)%Mo;
    b[0]=0;
}

ll h[N];

void get_exp(ll *a,ll *b,int n) {
    if (n==1) {b[0]=1;return;}
    get_exp(a,b,n>>1);
    get_ln(b,h,n);
    fo(i,0,n-1) h[i]=(a[i]-h[i]+Mo)%Mo;
    (h[0]=h[0]+1)%=Mo;
    int len=n<<1;
    fo(i,n,len-1) h[i]=b[i]=0;
    DFT(h,len,1);DFT(b,len,1);
    fo(i,0,len-1) b[i]=b[i]*h[i]%Mo;
    DFT(b,len,-1);
    fo(i,n,len-1) b[i]=0;
}

ll H[N];

void get_pow(ll *a,int n,int m) {
    get_ln(a,H,n);
    fo(i,0,n-1) H[i]=H[i]*m%Mo;
    get_exp(H,a,n);
}

int n,m,x,len;
ll F[N],G[N];

int main() {
    scanf("%d%d",&n,&m);
    for(len=1;len<=n;len<<=1);
    fo(i,1,m) {
        scanf("%d",&x);
        G[x-1]--;
    }
    G[0]++;
    get_Inv(G,F,len);
    get_pow(F,len,n);
    ll ans=F[n-1]*pwr(n,Mo-2)%Mo;
    printf("%lld\n",(ans+Mo)%Mo);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/alan_cty/article/details/81914993