• 有标号DAG计数(生成函数)


    有标号DAG计数(生成函数)

    luogu

    题解时间

    首先考虑暴力,很容易得出 $ f[ i ] = sumlimits_{ j = 1 }^{ i } ( -1 )^{ j - 1 } inom{ i }{ j } 2^{ j( i - j ) } f[ i-j ] $ 。

    相当于枚举度数为0的节点的个数,向不在这个集合里的点任意连边,之后需要容斥。

    考虑如何优化。

    $ j(i-j) = frac{ i^{ 2 } }{ 2 } - frac{ j^{ 2 } }{ 2 } - frac{ ( i - j )^{ 2 } }{ 2 } $ 。

    $ f[ i ] = sumlimits_{ j = 1 }^{ i } ( -1 )^{ j - 1 } frac{ i! }{ j!(i-j)! } frac{ ( sqrt{ 2 } )^{ i^{ 2 } } }{ ( sqrt{ 2 } )^{ j^{ 2 } } ( sqrt{ 2 } )^{ (i-j)^{ 2 } } } f[ i-j ] $ 。

    构造 $ F(x) = sumlimits_{ i = 0 }^{n} frac{ f_{ i } }{ i! sqrt{ 2 }^{ i^{ 2 } } } x^{ i } , G(x) = sumlimits_{ i = 0 }^{n} frac{ (-1)^{ i - 1 } }{ i! sqrt{ 2 }^{ i^{ 2 } } } x^{ i } $ ,

    有 $ F( x ) = F( x )G( x ) + 1 $ ,直接求逆。

    如果要求图必须是弱连通呢?

    直接对EGF取ln就好。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long lint;
    namespace RKK
    {
    const int N=300011,maxn=262144;
    const int mo=998244353,G=3,sqrt2=116195171;
    lint add(lint a,lint b){return (a+=b)>=mo?a-mo:a;}
    lint doadd(lint &a,lint b){if((a+=b)>=mo) a-=mo;}
    lint fpow(lint a,lint p){lint ret=1;while(p){if(p&1ll) ret=ret*a%mo;a=a*a%mo;p>>=1;}return ret;}
    lint wg[N],iwg[N];int rev[N],lastlen;
    inline void init(){for(int i=1;i<maxn;i<<=1) wg[i]=fpow(G,(mo-1)/(i<<1)),iwg[i]=fpow(wg[i],mo-2);}
    inline void getrev(int len){for(int i=1;i<len;i++)rev[i]=(rev[i>>1]>>1)|((i&1)*(len>>1));}
    inline void ntt(lint *a,int len,int tp)
    {
    	if(lastlen!=len) getrev(len),lastlen=len;
    	for(int i=0;i<len;i++)if(i<rev[i]) swap(a[i],a[rev[i]]);
    	for(int i=1;i<len;i<<=1)
    	{
    		lint w0=(~tp)?wg[i]:iwg[i];
    		for(int j=0;j<len;j+=(i<<1))
    		{
    			lint w=1;
    			for(int k=0;k<i;k++,(w*=w0)%=mo)
    			{
    				lint w1=a[j+k],w2=w*a[j+k+i]%mo;
    				a[j+k]=add(w1,w2),a[j+k+i]=add(w1,mo-w2);
    			}
    		}
    	}
    	lint ilen=fpow(len,mo-2);
    	if(tp==-1)for(int i=0;i<len;i++) (a[i]*=ilen)%=mo;
    }
    namespace poly
    {
    namespace inv
    {
    	lint a[N],b[N];
    	void work(lint *f,lint *g,int n)
    	{
    		g[0]=fpow(f[0],mo-2);
    		for(int len=1;len<n<<1;len<<=1)
    		{
    			memcpy(a,f,len*8),memcpy(b,g,len*8);
    			ntt(a,len<<1,1),ntt(b,len<<1,1);
    			for(int i=0;i<len<<1;i++) g[i]=b[i]*(2ll-a[i]*b[i]%mo+mo)%mo;
    			ntt(g,len<<1,-1),memset(g+len,0,len*8);
    		}
    		memset(a,0,n*16),memset(b,0,n*16);
    	}
    }
    namespace ln
    {
    	lint a[N],b[N];
    	void de(lint *f,int n){for(int i=0;i<n;i++) f[i]=f[i+1]*(i+1)%mo;f[n-1]=0;}
    	void ide(lint *f,int n){for(int i=n-2;i>=0;i--) f[i+1]=f[i]*fpow(i+1,mo-2)%mo;f[0]=0;}
    	void work(lint *f,lint *g,int n)
    	{
    		int len=n;
    		memcpy(a,f,len*8),de(a,len);
    		inv::work(f,b,len);
    		ntt(a,len<<1,1),ntt(b,len<<1,1);
    		for(int i=0;i<len<<1;i++) g[i]=a[i]*b[i]%mo;
    		ntt(g,len<<1,-1),ide(g,len);
    		memset(a,0,len*16),memset(b,0,len*16);
    	}
    }
    }
    int n;
    lint inv[N],fac[N],ifac[N];
    void sieve(int n)
    {
    	inv[0]=inv[1]=1;for(int i=2;i<=n;i++) inv[i]=inv[mo%i]*(mo-mo/i)%mo;
    	fac[0]=1;for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mo;
    	ifac[0]=1;for(int i=1;i<=n;i++) ifac[i]=ifac[i-1]*inv[i]%mo;
    }
    lint f[N],g[N],h[N];
    int main()
    {
    	scanf("%d",&n);init();
    	int len=1;while(len<=n) len<<=1;
    	sieve(len);
    	g[0]=1;for(int i=1;i<len;i++)
    	{
    		g[i]=ifac[i]*fpow(fpow(sqrt2,1ll*i*i%(mo-1)),mo-2)%mo;
    		if(i&1) g[i]=mo-g[i];
    	}
    	poly::inv::work(g,f,len);//求出不保证联通的
    	for(int i=0;i<len;i++) f[i]=f[i]*fpow(sqrt2,1ll*i*i%(mo-1))%mo;//不乘fac因为还要用egf直接去ln
    	poly::ln::work(f,h,len);
    	for(int i=1;i<=n;i++) printf("%lld
    ",h[i]*fac[i]%mo);
    	return 0;
    }
    }
    int main(){return RKK::main();}
    
  • 相关阅读:
    切换某个窗口为当前窗口并显示在最前面---非置顶
    C语言算法-求两直线夹角计算公式
    Qt编译时MinGW去掉对gcc动态库的依赖
    解决不能从 WTL::CString 转换为 ATL::CSimpleString & 的问题
    gcc编译器对宽字符的识别
    4月10日学习笔记——jQuery选择器
    HTML5
    4月8日学习笔记(js基础)
    网站易用性2
    网站易用性
  • 原文地址:https://www.cnblogs.com/rikurika/p/13378144.html
Copyright © 2020-2023  润新知