• 银联高校极客挑战赛 初赛 第二场 C. 异世界幻想 purfer序列+第二类斯特林数


    题意:给出一个n表示点数,请问由n个节点构成的所有有标号无根树的叶子节点数总和。

    首先这个“有标号无根树”的描述就强烈暗示与purfer序列有关了,每一个不同的purfer序列唯一地表示一种树的构成,并且这个序列对答案的贡献等于序列中没有出现过的数字的个数。

    然后我们就可以去求每个恰好出现过k个颜色的序列的方案数,我们可以发现这个方案数恰好为C(n,k)*T(n,k)*k! T为第二类斯特林数,第二类斯特林数我们需要用NTT卷积的方式nlogn地求出,可以去找个板子来求。

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    const int N=4e5+10;
    const LL P=998244353,yg=3;
    LL n,fac[N],inv[N],f[N],g[N],S2[N];
    LL bin[N];
    
    LL power(LL x,LL p) {
        LL ret=1;
        for (;p;p>>=1) {
            if (p&1) ret=(ret*x)%P;
            x=(x*x)%P;
        }
        return ret;
    }
    
    void NTT(LL *a,LL n,LL op) {  //NTT:系数a数组,长度为n,op=1求值op=-1插值 
        for(LL i=0;i<n;i++) bin[i]=(bin[i>>1]>>1)|((i&1)*(n>>1));
        for(LL i=0;i<n;i++) if(i<bin[i]) swap(a[i],a[bin[i]]);
        for(LL i=1;i<n;i<<=1) {
            LL wn=power(yg,op==1?(P-1)/(2*i):(P-1)-(P-1)/(2*i)),w,t;
            for(LL j=0;j<n;j+=i<<1) {
                w=1;
                for(LL k=0;k<i;k++) {
                    t=a[i+j+k]*w%P;w=w*wn%P;
                    a[i+j+k]=(a[j+k]-t+P)%P;a[j+k]=(a[j+k]+t)%P;
                }
            }
        }
        if(op==-1) {
            LL Inv=power(n,P-2);
            for(LL i=0;i<n;i++) a[i]=a[i]*Inv%P;
        }
    }
    long long C(long long n,long long m){return fac[n]*inv[m]%P*inv[n-m]%P;}
    int main()
    {
        cin>>n;
        if(n==1)
        {
            printf("1
    ");
            return 0;
        }
        if(n==2)
        {
            printf("2
    ");
            return 0;
        }
        fac[0]=inv[0]=1;
        for (int i=1;i<=n;i++) fac[i]=fac[i-1]*i%P,inv[i]=power(fac[i],P-2);
        for (int i=0;i<=n;i++) f[i]=(power(-1,i)+P)%P*inv[i]%P;
        for (int i=0;i<=n;i++) g[i]=power(i,n-2)*inv[i]%P;
        
        LL N=n-1;
        LL len=1;while(len<(n+1)<<1) len<<=1;
        
        NTT(f,len,1); NTT(g,len,1);
        for (int i=0;i<len;i++) S2[i]=(f[i]*g[i])%P;  //求f.g的卷积为S2 
        NTT(S2,len,-1);
        
        long long ans=0;
        for(int i=1;i<=n-2;i++)
        {
            long long d=fac[i]*S2[i];
            d%=P;
            //printf("%d %lld %lld
    ",n-i,d,S2[i]);
            ans+=d*C(n,i)%P*(n-i)%P;
            ans%=P;
        }
        ans%=P,ans+=P,ans%=P;
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    LA 6621 /ZOJ 3736 Pocket Cube 打表+暴力
    UVA 10273
    UVA 10158 并查集的经典应用
    CodeForces 382B 数学推导
    UVA 10806 最小费用最大流
    UVA 10330 最大流
    图论:匹配与覆盖+独立集 团与支配集
    sdut oj 操作系统实验--SSTF磁盘调度算法【操作系统算法】
    【转载】单调队列学习
    poj 3006 Dirichlet's Theorem on Arithmetic Progressions【素数问题】
  • 原文地址:https://www.cnblogs.com/megalovania/p/11222009.html
Copyright © 2020-2023  润新知