zoukankan      html  css  js  c++  java
  • 有标号的DAG计数(FFT)

    有标号的DAG计数系列

    有标号的DAG计数I

    题意

    给定一正整数(n),对(n)个点有标号的有向无环图(可以不连通)进行计数,输出答案(mod 10007)的结果。(nle 5000)

    题解

    显然是(O(n^2))来做。
    (f(i))表示(i)个点有标号的有向无环图的个数。而(DAG)中的特殊点显然只有两种,要么是出度为(0),要么入度为(0)。随便枚举哪一种都行,这里枚举入度为(0)的点。
    那么得到式子:

    [f(n)=sum_{i=1}^nC_n^if(n-i)2^{i(n-i)} ]

    显然这样子枚举出来的并不是入度个数恰好为枚举个数的答案,所以需要容斥,也就是:

    [f(i)=sum_{j=1}^n(-1)^{j-1}C_i^jf(i-j)2^{j(i-j)} ]

    (O(n^2))暴力(dp)即可。

    有标号的DAG计数II

    题意

    给定一正整数(n),对(n)个点有标号的有向无环图(可以不连通)进行计数,输出答案(mod 998244353)的结果。(nle 10^5)

    题解

    推导同上题式子。考虑接着拆。
    首先把(2^{j(i-j)})给拆了,(j(i-j)=i^2/2-j^2/2-(i-j)^2/2)
    这样子令(t=sqrt 2),也就是(2)在模意义下的二次剩余。
    接着拆式子:

    [egin{aligned} f(i)&=sum_{j=1}^n(-1)^{j-1}C_i^jf(i-j)2^{j(i-j)}\ &=sum_{j=1}^n(-1)^{j-1}frac{i!}{j!(i-j)!}f(i-j)t^{i^2-j^2-(i-j)^2}\ &=sum_{j=1}^n frac{(-1)^{j-1}}{j!t^{j^2}}*frac{f(i-j)}{(i-j)!t^{(i-j)^2}}*i!*t^{i^2}\ frac{f(i)}{i!t^{i^2}}&=sum_{j=1}^n frac{(-1)^{j-1}}{j!t^{j^2}}*frac{f(i-j)}{(i-j)!t^{(i-j)^2}} end{aligned} ]

    (F(x))(frac{f(i)}{i!t^{i^2}})的生成函数,(G(x))(frac{(-1)^{i-1}}{i!t^{i^2}})的生成函数,那么上面的等式写成:(F(x)=G(x)F(x)+1),因为卷积之后漏掉了(F(0))
    那么解出(F(x)=frac{1}{1-G(x)}),多项式求逆即可。

    有标号的DAG计数III

    题意

    给定一正整数(n),对(n)个点有标号的有向无环图进行计数,这里加一个限制:此图必须是弱连通图。输出答案(mod 10007)的结果。(nle 5000)

    题解

    又回到了一个(O(n^2))的做法。设答案为(g(i))。那么考虑这里和前面的区别在哪儿?这里要求弱连通。那么连通和不连通的考虑方法一般就是总数减去不合法,那么考虑什么东西是不合法的。

    [g(i)=f(i)-sum_{j=1}^{i-1}C_{i-1}^{j-1}g(j)f(i-j) ]

    为啥呢?因为一旦不是弱连通了,那么必定有两个以上的联通块。我们枚举其中的一个包含(1)号点的联通块大小,那么这个方案数是(g(j)),而其他点随意构成(DAG),这样就是上述的式子了。
    所以把(I)的代码蒯过来再加一个(dp)(g)就好了。

    有标号的DAG计数IV

    题意

    给定一正整数(n),对(n)个点有标号的有向无环图进行计数,这里加一个限制:此图必须是弱连通图。输出答案(mod 998244353)的结果。

    题解

    拆式子啊QwQ。

    [egin{aligned} g(i)&=f(i)-sum_{j=1}^{i-1}C_{i-1}^{j-1}g(j)f(i-j)\ &=f(i)-sum_{j=1}^{i-1}frac{(i-1)!}{(j-1)!(i-j)!}g(j)f(i-j)\ frac{g(i)}{(i-1)!}&=frac{f(i)}{(i-1)!}-sum_{j=1}^{i-1}frac{g(j)}{(j-1)!}frac{f(i-j)}{(i-j)!} end{aligned} ]

    这样子可以构建三个生成函数
    (G(x)=sum frac{g(i)}{(i-1)!}x^i)(F(x)=sum frac{f(i)}{(i-1)!}x^i)(H(x)=sum frac{f(i)}{i!}x^i)。其中(sum)都表示(sum_{i=1}^{infty})
    卷积一下就是(G(x)=F(x)-G(x)*H(x))
    化简一下就是(G(x)=frac{F(x)}{1+H(x)})
    多项式求逆即可。

    I

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define MOD 10007
    #define MAX 5050
    int n,f[MAX],bin[MAX*MAX],jc[MAX],jv[MAX],inv[MAX];
    int C(int n,int m){return jc[n]*jv[m]%MOD*jv[n-m]%MOD;}
    void add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;}
    int main()
    {
    	scanf("%d",&n);f[0]=jc[0]=jv[0]=inv[0]=inv[1]=bin[0]=1;
    	for(int i=2;i<=n;++i)inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD;
    	for(int i=1;i<=n;++i)jc[i]=jc[i-1]*i%MOD;
    	for(int i=1;i<=n;++i)jv[i]=jv[i-1]*inv[i]%MOD;
    	for(int i=1;i<=n*n;++i)bin[i]=2*bin[i-1]%MOD;
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=i;++j)
    		{
    			int tmp=C(i,j)*f[i-j]%MOD*bin[j*(i-j)]%MOD;
    			if(j&1)add(f[i],tmp);else add(f[i],MOD-tmp);
    		}
    	printf("%d
    ",f[n]);
    	return 0;
    }
    

    II

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define MOD 998244353
    #define REM 882049182
    #define MAX 300000
    int fpow(int a,int b)
    {
    	int s=1;
    	while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}
    	return s;
    }
    int r[MAX],W[MAX];
    void NTT(int *P,int opt,int N)
    {
    	int l=0;for(int i=1;i<N;i<<=1)++l;
    	for(int i=0;i<N;++i)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    	for(int i=0;i<N;++i)if(i<r[i])swap(P[i],P[r[i]]);
    	for(int i=1;i<N;i<<=1)
    	{
    		int w=fpow(3,(MOD-1)/(i<<1));W[0]=1;
    		for(int k=1;k<i;++k)W[k]=1ll*W[k-1]*w%MOD;
    		for(int p=i<<1,j=0;j<N;j+=p)
    			for(int k=0;k<i;++k)
    			{
    				int X=P[j+k],Y=1ll*W[k]*P[i+j+k]%MOD;
    				P[j+k]=(X+Y)%MOD;P[i+j+k]=(X+MOD-Y)%MOD;
    			}
    	}
    	if(opt==-1)
    	{
    		reverse(&P[1],&P[N]);
    		for(int i=0,inv=fpow(N,MOD-2);i<N;++i)P[i]=1ll*P[i]*inv%MOD;
    	}
    }
    int A[MAX],B[MAX];
    void Inv(int *a,int *b,int len)
    {
    	if(len==1){b[0]=fpow(a[0],MOD-2);return;}
    	Inv(a,b,len>>1);
    	for(int i=0;i<len;++i)A[i]=a[i],B[i]=b[i];
    	NTT(A,1,len<<1);NTT(B,1,len<<1);
    	for(int i=0;i<len<<1;++i)A[i]=1ll*A[i]*B[i]%MOD*B[i]%MOD;
    	NTT(A,-1,len<<1);
    	for(int i=0;i<len;++i)b[i]=(b[i]+b[i])%MOD;
    	for(int i=0;i<len;++i)b[i]=(b[i]+MOD-A[i])%MOD;
    	for(int i=0;i<len<<1;++i)A[i]=B[i]=0;
    }
    int jc[MAX],jv[MAX],inv[MAX];
    int N,n,F[MAX],G[MAX];
    int main()
    {	
    	scanf("%d",&n);jc[0]=jv[0]=inv[0]=inv[1]=1;
    	for(int i=1;i<=n;++i)jc[i]=1ll*jc[i-1]*i%MOD;
    	for(int i=2;i<=n;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
    	for(int i=1;i<=n;++i)jv[i]=1ll*jv[i-1]*inv[i]%MOD;
    	for(N=1;N<=n;N<<=1);G[0]=1;int t=fpow(REM,MOD-2);
    	for(int i=1;i<N;++i)G[i]=1ll*jv[i]*fpow(t,1ll*i*i%(MOD-1))%MOD;
    	for(int i=1;i<N;++i)if(i&1)G[i]=MOD-G[i];
    	Inv(G,F,N);
    	printf("%lld
    ",1ll*F[n]*jc[n]%MOD*fpow(REM,1ll*n*n%(MOD-1))%MOD);
    	return 0;
    }
    

    III

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define MOD 10007
    #define MAX 5050
    int n,f[MAX],g[MAX],bin[MAX*MAX],jc[MAX],jv[MAX],inv[MAX];
    int C(int n,int m){return jc[n]*jv[m]%MOD*jv[n-m]%MOD;}
    void add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;}
    int main()
    {
    	scanf("%d",&n);f[0]=jc[0]=jv[0]=inv[0]=inv[1]=bin[0]=1;
    	for(int i=2;i<=n;++i)inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD;
    	for(int i=1;i<=n;++i)jc[i]=jc[i-1]*i%MOD;
    	for(int i=1;i<=n;++i)jv[i]=jv[i-1]*inv[i]%MOD;
    	for(int i=1;i<=n*n;++i)bin[i]=2*bin[i-1]%MOD;
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=i;++j)
    		{
    			int tmp=C(i,j)*f[i-j]%MOD*bin[j*(i-j)]%MOD;
    			if(j&1)add(f[i],tmp);else add(f[i],MOD-tmp);
    		}
    	for(int i=0;i<=n;++i)g[i]=f[i];
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<i;++j)
    			add(g[i],MOD-C(i-1,j-1)*g[j]%MOD*f[i-j]%MOD);
    	printf("%d
    ",g[n]);
    	return 0;
    }
    

    IV

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define MOD 998244353
    #define REM 882049182
    #define MAX 300000
    int fpow(int a,int b)
    {
    	int s=1;
    	while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}
    	return s;
    }
    int r[MAX],W[MAX];
    void NTT(int *P,int opt,int N)
    {
    	int l=0;for(int i=1;i<N;i<<=1)++l;
    	for(int i=0;i<N;++i)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    	for(int i=0;i<N;++i)if(i<r[i])swap(P[i],P[r[i]]);
    	for(int i=1;i<N;i<<=1)
    	{
    		int w=fpow(3,(MOD-1)/(i<<1));W[0]=1;
    		for(int k=1;k<i;++k)W[k]=1ll*W[k-1]*w%MOD;
    		for(int p=i<<1,j=0;j<N;j+=p)
    			for(int k=0;k<i;++k)
    			{
    				int X=P[j+k],Y=1ll*W[k]*P[i+j+k]%MOD;
    				P[j+k]=(X+Y)%MOD;P[i+j+k]=(X+MOD-Y)%MOD;
    			}
    	}
    	if(opt==-1)
    	{
    		reverse(&P[1],&P[N]);
    		for(int i=0,inv=fpow(N,MOD-2);i<N;++i)P[i]=1ll*P[i]*inv%MOD;
    	}
    }
    int A[MAX],B[MAX];
    void Inv(int *a,int *b,int len)
    {
    	if(len==1){b[0]=fpow(a[0],MOD-2);return;}
    	Inv(a,b,len>>1);
    	for(int i=0;i<len;++i)A[i]=a[i],B[i]=b[i];
    	NTT(A,1,len<<1);NTT(B,1,len<<1);
    	for(int i=0;i<len<<1;++i)A[i]=1ll*A[i]*B[i]%MOD*B[i]%MOD;
    	NTT(A,-1,len<<1);
    	for(int i=0;i<len;++i)b[i]=(b[i]+b[i])%MOD;
    	for(int i=0;i<len;++i)b[i]=(b[i]+MOD-A[i])%MOD;
    	for(int i=0;i<len<<1;++i)A[i]=B[i]=0;
    }
    int jc[MAX],jv[MAX],inv[MAX];
    int N,n,F[MAX],G[MAX],H[MAX],P[MAX];
    int main()
    {	
    	scanf("%d",&n);jc[0]=jv[0]=inv[0]=inv[1]=1;
    	for(int i=1;i<=n;++i)jc[i]=1ll*jc[i-1]*i%MOD;
    	for(int i=2;i<=n;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
    	for(int i=1;i<=n;++i)jv[i]=1ll*jv[i-1]*inv[i]%MOD;
    	for(N=1;N<=n;N<<=1);G[0]=1;int t=fpow(REM,MOD-2);
    	for(int i=1;i<N;++i)G[i]=1ll*jv[i]*fpow(t,1ll*i*i%(MOD-1))%MOD;
    	for(int i=1;i<N;++i)if(i&1)G[i]=MOD-G[i];
    	Inv(G,F,N);
    	for(int i=1;i<N;++i)F[i]=1ll*F[i]*jc[i]%MOD*fpow(REM,1ll*i*i%(MOD-1))%MOD;
    	for(int i=1;i<N;++i)H[i]=1ll*F[i]*jv[i]%MOD;H[0]=1;
    	for(int i=1;i<N;++i)F[i]=1ll*F[i]*jv[i-1]%MOD;F[0]=0;
    	Inv(H,P,N);
    	NTT(F,1,N<<1);NTT(P,1,N<<1);
    	for(int i=0;i<N<<1;++i)G[i]=1ll*F[i]*P[i]%MOD;
    	NTT(G,-1,N<<1);
    	printf("%lld
    ",1ll*G[n]*jc[n-1]%MOD);
    	return 0;
    }
    
  • 相关阅读:
    【Unity】近期整理Unity4.x 项目升级Unity5.0 过程中出现的各种常见问题,与大家共享。
    extjs Combox 调用数据
    CSDN博客2014年4月24日清理缓存
    在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误。未找到或无法訪问server。请验证实例名称是否正确而且 SQL Server 已配置为同意远程连接。
    海思 3520D 移植Qt4.5.3 一
    Android 输入框限制字符输入数
    Making User-Managed Backups-17.4、Making User-Managed Backups of Online Tablespaces and Datafiles
    spring 使用外部属性文件
    mysql字符串替换
    maven3+eclipse搭建webAPP企业级实战《一》
  • 原文地址:https://www.cnblogs.com/cjyyb/p/10134575.html
Copyright © 2011-2022 走看看