zoukankan      html  css  js  c++  java
  • 【BZOJ3684】大朋友和多叉树 【拉格朗日反演】【FFT/NTT】

    题解
    其实就是一个拉格朗日反演+多项式全家桶。
    拉格朗日反演:如果两个多项式f,g满足g(f(x))=x,则有

    [xn]f(x)=1n[x1]1g(x)n

    我们更常用的形式是
    [xn]f(x)=1n[xn1]1g(x)n

    其中g(x)=g(x)/x。因此我们需要钦点g没有常数项。
    在这题内,我们设f(x)为点权为x的方案总数。则答案为f(s)
    我们设F(x)=if(i)。则有
    F(x)=x+kDF(x)k

    就是自己一个点一棵树的情况加上选若干个儿子的情况。
    移项得到
    F(x)kDF(x)k=x

    我们设G(x)=xkDxk
    则满足G(F(x))=x
    拉格朗日反演就好了。
    这里的多项式快速幂,我们可以先求ln,每一项都乘一下,再求exp。快速幂之后再求个逆。
    全部操作都是迭代版本的。
    时间复杂度O(nlog2n)

    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=270005,mod=950009857;
    int s,n,m,x,a[N],inv[N],rev[N];
    int fastpow(int a,int x){
        int res=1;
        while(x){
            if(x&1){
                res=1LL*res*a%mod;
            }
            x>>=1;
            a=1LL*a*a%mod;
        }
        return res;
    }
    void ntt(int a[],int n,int dft){
        for(int i=0;i<n;i++){
            rev[i]=(rev[i>>1]>>1)|((i&1)*(n>>1));
            if(i<rev[i]){
                swap(a[i],a[rev[i]]);
            }
        }
        for(int i=1;i<n;i<<=1){
            int wn=fastpow(7,(mod-1)/i/2);
            if(dft==-1){
                wn=fastpow(wn,mod-2);
            }
            for(int j=0;j<n;j+=(i<<1)){
                int w=1,x,y;
                for(int k=j;k<j+i;k++,w=1LL*w*wn%mod){
                    x=a[k];
                    y=1LL*w*a[k+i]%mod;
                    a[k]=x+y<mod?x+y:x+y-mod;
                    a[k+i]=x-y>=0?x-y:x-y+mod;
                }
            }
        }
        if(dft==-1){
            int inv=fastpow(n,mod-2);
            for(int i=0;i<n;i++){
                a[i]=1LL*a[i]*inv%mod;
            }
        }
    }
    void inverse(int a[],int n){
        static int b[N],c[N],d[N];
        b[0]=fastpow(a[0],mod-2);
        for(int k=2;k<=n;k<<=1){
            for(int i=0;i<(k<<1);i++){
                if(i<k){
                    c[i]=a[i];
                }else{
                    c[i]=0;
                }
                if(i<(k>>1)){
                    d[i]=b[i];
                }else{
                    d[i]=0;
                }
            }
            ntt(c,k<<1,1);
            ntt(d,k<<1,1);
            for(int i=0;i<(k<<1);i++){
                c[i]=(2*d[i]%mod-1LL*c[i]*d[i]%mod*d[i]%mod+mod)%mod;
            }
            ntt(c,k<<1,-1);
            for(int i=0;i<k;i++){
                b[i]=c[i];
            }
        }
        for(int i=0;i<n;i++){
            a[i]=b[i];
        }
    }
    void dao(int a[],int n){
        for(int i=0;i<n-1;i++){
            a[i]=1LL*a[i+1]*(i+1)%mod;
        }
        a[n-1]=0;
    }
    void ji(int a[],int n){
        for(int i=n-1;i>0;i--){
            a[i]=1LL*a[i-1]*inv[i]%mod;
        }
        a[0]=0;
    }
    void getln(int a[],int n){
        static int b[N];
        for(int i=0;i<(n<<1);i++){
            if(i<n){
                b[i]=a[i];
            }else{
                b[i]=a[i]=0;
            }
        }
        dao(a,n<<1);
        inverse(b,n);
        ntt(a,n<<1,1);
        ntt(b,n<<1,1);
        for(int i=0;i<(n<<1);i++){
            a[i]=1LL*a[i]*b[i]%mod;
        }
        ntt(a,n<<1,-1);
        ji(a,n<<1);
    }
    void getexp(int a[],int n){
        static int b[N],c[N];
        b[0]=1;
        for(int k=2;k<=n;k<<=1){
            for(int i=0;i<(k<<1);i++){
                if(i<(k>>1)){
                    c[i]=b[i];
                }else{
                    c[i]=0;
                }
            }
            getln(c,k);
            for(int i=0;i<k;i++){
                c[i]=(a[i]+(i==0)+mod-c[i])%mod;
            }
            ntt(c,k<<1,1);
            ntt(b,k<<1,1);
            for(int i=0;i<(k<<1);i++){
                c[i]=1LL*c[i]*b[i]%mod;
            }
            ntt(c,k<<1,-1);
            ntt(b,k<<1,-1);
            for(int i=0;i<k;i++){
                b[i]=c[i];
            }
        }
        for(int i=0;i<n;i++){
            a[i]=b[i];
        }
    }
    int main(){
        scanf("%d%d",&s,&m);
        a[0]=1;
        for(int i=1;i<=m;i++){
            scanf("%d",&x);
            a[x-1]=(a[x-1]+mod-1)%mod;
        }
        for(n=1;n<=s;n<<=1);
        inv[1]=1;
        for(int i=2;i<n;i++){
            inv[i]=1LL*(mod-mod/i)*inv[mod%i]%mod;
        }
        getln(a,n);
        for(int i=0;i<n;i++){
            a[i]=1LL*a[i]*s%mod;
        }
        getexp(a,n);
        inverse(a,n);
        printf("%lld
    ",1LL*a[s-1]*inv[s]%mod);
        return 0;
    }
  • 相关阅读:
    NetSuite Batch Process Status
    NetSuite generated bank files and the Bank Reconciliation process
    Global Search file content in Gitlab repositories, search across repositories, search across all files
    FedEx Package Rate Integration with NetSuite direct integrate by WebServices
    git Merge branches
    git tag and NetSuite deployment tracking
    API 读写cookie的方法
    C# 生成缩略图
    解决jquery操作checkbox全选全不选无法勾选问题
    JS读取写入删除Cookie方法
  • 原文地址:https://www.cnblogs.com/2016gdgzoi471/p/9476834.html
Copyright © 2011-2022 走看看