zoukankan      html  css  js  c++  java
  • [CSAcademy]Colored Forests

    csacademy

    description

    (M)种颜色编号为(1-M)。现给树上的每个点染上这(M)种颜色中的一种,定义一棵树是(mbox{colorful})的当且仅当这棵树上(M)种颜色都出现了至少一次。定义一片森林是(mbox{colorful})的当且仅当其中的每一棵树都是(mbox{colorful})的。
    (n)点带标号的(mbox{colorful})的森林的数量模(924844033)
    (nle10^5,mle50)
    (Hint:924844033=2^{21} imes441+1),它的原根是(5)

    sol

    首先求出(n)点构成一棵(mbox{colorful})的树的方案数(g_n)

    [g_n=egin{cases}1&n=1\n^{n-2} imes S(n,m) imes m!&nge2end{cases} ]

    (n^{n-2})是带标号完全图生成树的方案数,后面的第二类斯特林数乘阶乘的组合意义就是把(n)个不同的球放入(m)个不同的盒子里且不允许空盒的方案数。
    然后设(f_n)表示答案,考虑新加入的第(n)号点和那些点连通构成一棵树:

    [f_n=sum_{i=1}^ng_iinom{n-1}{i-1}f_{n-i} ]

    把组合数拆开就是一个卷积的形式,直接分治法法塔即可。复杂度(O(nlog^2n))
    懒得写求逆了

    code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int gi(){
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    const int N = 4e5+5;
    const int mod = 924844033;
    int n,m,jc[N],jcn[N],S[N][105],g[N],f[N],rev[N],og[N],x[N],y[N];
    int fastpow(int a,int b){
    	int res=1;
    	while(b){if(b&1)res=1ll*res*a%mod;a=1ll*a*a%mod;b>>=1;}
    	return res;
    }
    void ntt(int *P,int opt,int len){
    	int l=0;while((1<<l)<len)++l;--l;
    	for (int i=0;i<len;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<l);
    	for (int i=0;i<len;++i) if (i<rev[i]) swap(P[i],P[rev[i]]);
    	for (int i=1;i<len;i<<=1){
    		int W=fastpow(5,(mod-1)/(i<<1));
    		if (opt==-1) W=fastpow(W,mod-2);
    		og[0]=1;for (int j=1;j<i;++j) og[j]=1ll*og[j-1]*W%mod;
    		for (int p=i<<1,j=0;j<len;j+=p)
    			for (int k=0;k<i;++k){
    				int x=P[j+k],y=1ll*og[k]*P[j+k+i]%mod;
    				P[j+k]=(x+y)%mod;P[j+k+i]=(x-y+mod)%mod;
    			}
    	}
    	if (opt==-1) for (int i=0,Inv=fastpow(len,mod-2);i<len;++i) P[i]=1ll*P[i]*Inv%mod;
    }
    void solve(int l,int r){
    	if (l==r) return;int mid=l+r>>1;solve(l,mid);
    	int len=1;while(len<=r-l+1)len<<=1;
    	for (int i=0;i<len;++i) x[i]=y[i]=0;
    	for (int i=l;i<=mid;++i) x[i-l]=1ll*f[i]*jcn[i]%mod;
    	for (int i=1;i<=r-l;++i) y[i-1]=1ll*g[i]*jcn[i-1]%mod;
    	ntt(x,1,len);ntt(y,1,len);
    	for (int i=0;i<len;++i) x[i]=1ll*x[i]*y[i]%mod;
    	ntt(x,-1,len);
    	for (int i=mid+1;i<=r;++i) f[i]=(f[i]+1ll*x[i-l-1]*jc[i-1])%mod;
    	solve(mid+1,r);
    }
    int main(){
    	n=gi();m=gi();
    	jc[0]=jcn[0]=1;
    	for (int i=1;i<=n;++i) jc[i]=1ll*jc[i-1]*i%mod;
    	jcn[n]=fastpow(jc[n],mod-2);
    	for (int i=n;i;--i) jcn[i-1]=1ll*jcn[i]*i%mod;
    	S[0][0]=1;
    	for (int i=1;i<=n;++i)
    		for (int j=1;j<=i&&j<=m;++j)
    			S[i][j]=(1ll*S[i-1][j]*j+S[i-1][j-1])%mod;
    	for (int i=1;i<=n;++i)
    		g[i]=1ll*(i==1?1:fastpow(i,i-2))*S[i][m]%mod*jc[m]%mod;
    	f[0]=1;solve(0,n);
    	for (int i=1;i<=n;++i) printf("%d
    ",f[i]);return 0;
    }
    
  • 相关阅读:
    SDN第七次上机作业
    SDN第六次上机作业
    SDN第五次上机实验
    SDN阅读作业(二)
    软件评测——腾讯音视频
    SDN上机第四次作业
    SDN上机第三次作业
    SDN阅读作业
    SpringBoot整合Swagger2
    JavaWeb项目前后端分离
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/9415037.html
Copyright © 2011-2022 走看看