zoukankan      html  css  js  c++  java
  • Codechef TREDEG Trees and Degrees

    Link
    看到全是度数相关的计数就可以考虑Prüfer序列。
    一个点的度数就是其在Prüfer序列中的出现次数(+1),而一个Prüfer序列的贡献就是其所有元素出现次数(+1)的乘积,我们可以把乘积拆开dp。
    (f_{x,i})表示考虑前(x)个点,Prüfer序列长度为(i)的答案之和。
    边界就是(f_{0,0}=1),答案就是(f_{n,n+2})
    转移非常显然,枚举(x)的出现次数得到(f_{x,i}=sumlimits_{j=0}^i{ichoose j}(j+1)^Kf_{x-1,i-j})
    显然这是个卷积的形式:(frac{f_{x,k}}{k!}=sumlimits_{i+j=k}frac{(i+1)^K}{i!}frac{f_{x-1,j}}{j!})
    (P(x)=sumlimits_{i=0}^{n-2}frac{(i+1)^K}{i!}x^i),那么答案就是(frac{[x^{n-2}]P(x)^n(n-2)!}{n^{n-2}}),可以倍增快速幂解决。
    然后考虑(K=1)的特殊情况,此时(P(x)=sumlimits_{i=0}^{n-2}frac{i+1}{i!}x^i=(x+1)e^x),因此(P(x)^n=(x+1)^ne^{nx}=(sumlimits_{i=0}^n{nchoose i}x^i)(sumlimits_{i=0}^nfrac{n^i}{i!}x^i))([x^{n-2}]P(x)^n=sumlimits_{i=0}^{n-2}{nchoose i+2}frac{n^i}{i!}),直接(O(n))计算即可。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    const int N=2000007,M=262145,P=998244353;
    int read(){int x;scanf("%d",&x);return x;}
    int inc(int a,int b){return a+=b-P,a+(a>>31&P);}
    int dec(int a,int b){return a-=b,a+(a>>31&P);}
    int mul(int a,int b){return 1ll*a*b%P;}
    int pow(int a,int k=P-2){int r=1;for(;k;k>>=1,a=mul(a,a))if(k&1)r=mul(a,r);return r;}
    int n,k,lim,fac[N],ifac[N],rev[M],w[M],E[M],I[M];
    void init()
    {
        fac[0]=1;
        for(int i=1;i<=2000000;++i) fac[i]=mul(fac[i-1],i);
        ifac[2000000]=pow(fac[2000000]);
        for(int i=2000000;i;--i) ifac[i-1]=mul(ifac[i],i);
    }
    void init(int n)
    {
        lim=1<<(32-__builtin_clz(n)),w[lim>>1]=1;int g=pow(3,P/lim);
        for(int i=1;i<lim;++i) rev[i]=(rev[i>>1]>>1)|(i&1? lim>>1:0);
        w[lim>>1]=1;
        for(int i=(lim>>1)+1;i<lim;++i) w[i]=mul(w[i-1],g);
        for(int i=(lim>>1)-1;i;--i) w[i]=w[i<<1];
    }
    void NTT(int*a,int f)
    {
        if(!~f) std::reverse(a+1,a+lim);
        for(int i=0;i<lim;++i) if(i<rev[i]) std::swap(a[i],a[rev[i]]);
        for(int i=1;i<lim;i<<=1) for(int j=0,l=i<<1;j<lim;j+=l) for(int k=0,x;k<i;++k) x=mul(a[i+j+k],w[i+k]),a[i+j+k]=dec(a[j+k],x),a[j+k]=inc(a[j+k],x);
        if(!~f) for(int i=0,x=P-P/lim;i<lim;++i) a[i]=mul(a[i],x);
    }
    void solve1()
    {
        int ans=0;
        for(int i=0,t=1;i<=n-2;++i) ans=inc(ans,1ll*fac[n]*ifac[i+2]%P*ifac[n-i-2]%P*t%P*ifac[i]%P),t=mul(t,n);
        printf("%d
    ",mul(mul(ans,fac[n-2]),pow(pow(n,n-2))));
    }
    void solve2()
    {
        init(2*n-4),memset(E+n-1,0,(lim-n+4)<<2);
        for(int i=0;i<=n-2;++i) E[i]=mul(pow(i+1,k),ifac[i]);
        NTT(E,1),std::fill(I,I+lim,1);
        for(int t=n;t;t>>=1)
        {
    	if(t&1)
    	{
    	    for(int i=0;i<lim;++i) I[i]=mul(I[i],E[i]);
    	    NTT(I,-1),memset(I+n-1,0,(n-2)<<2),NTT(I,1);
    	}
    	for(int i=0;i<lim;++i) E[i]=mul(E[i],E[i]);
    	NTT(E,-1),memset(E+n-1,0,(n-2)<<2),NTT(E,1);
        }
        NTT(I,-1),printf("%d
    ",mul(mul(I[n-2],fac[n-2]),pow(pow(n,n-2))));
    }
    int main(){init();for(int T=read();T;--T) n=read(),k=read(),k==1? solve1():solve2();}
    
  • 相关阅读:
    vb代码控制 Excel锁定单元格
    SendMessage
    vb 中Treeview控件的一些问题!
    NGWS runtime C# 开始学习 第一天 (2006.6.7)
    DTS Transform Data Task的使用
    GetTickCount
    ASP.NET 2.0 中Login控件的使用
    core dump解析(2)
    tcp滑动窗口机制
    linux 查看文件夹大小 du命令
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12257454.html
Copyright © 2011-2022 走看看