zoukankan      html  css  js  c++  java
  • Tibbar的后花园(生成函数,多项式exp)

    Tibbar的后花园(多项式exp)

    这篇文章仅限于没有入门生成函数的蒟蒻读,dalao勿喷

    题目的数据范围是\(n< 2^{20}\)

    对于联通块求

    题目给出的限制,其实就是对于每一个联通块

    1.不存在一个点度数\(\ge 3\)

    2.不存在一个长度为\(3\)的倍数的环

    可以看到,一个大小为\(n\)的联通块,合法方案只有为一条链,或者一个长度不为3的倍数的环

    \(f_n\)为大小为\(n\)的联通块方案数,则

    \(f_n=\left\{\begin{aligned}1 && n\leq 2 \\ \frac{n!}{2}+[n \mod 3\ne 0](\frac{(n-1)!}{2}) && n\ge 3\end{aligned}\right.\)

    即链和环的个数

    对于图求

    如果采用普通的分治+NTT枚举每个联通块大小,复杂度为\(O(n\log ^2n)\),显然无法通过这个题

    考虑构造生成函数快速求解

    可以看到,如果排列\(n\)个点,每个点生成\(m\)个大小为\(a_i(\sum a_i=n)\)的联通块,那么答案是

    \(\sum \frac{n!}{m!} \Pi \frac{f_{a_i}}{a_i!}\)

    即除去联通块内的排列,联通块之间的排列

    \(g_n=\sum \frac{f_i}{i!}x^i\)

    那么答案可以转化为

    \[n![x^n](\sum_{i=0}^{\infty} \frac{g^i}{i!}) \]

    就是\(i\)次累乘(叠加了\(i\)个联通块)之后,第\(n\)项的系数再乘上少掉的阶乘

    然后由于

    \(\sum \frac{x^i}{i!}=e^x\)

    所以就是求出\(n![x^n]e^{g(x)}\)

    多项式exp我跑得血慢啊

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cctype>
    #include<vector>
    #include<cassert>
    using namespace std;
    
    //#pragma GCC optimize(2)
    #pragma GCC optimize(3)
    
    #define Mod1(x) ((x>=P)&&(x-=P))
    #define Mod2(x) ((x<0)&&(x+=P))
    
    #define reg register
    typedef long long ll;
    #define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
    #define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i)
    
    #define pb push_back
    template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
    template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }
    
    char IO;
    int rd(){
    	int s=0;
    	int f=0;
    	while(!isdigit(IO=getchar())) if(IO=='-') f=1;
    	do s=(s<<1)+(s<<3)+(IO^'0');
    	while(isdigit(IO=getchar()));
    	return f?-s:s;
    }
    
    const int N=(1<<21)+10,P=1004535809;
    
    int n;
    
    ll qpow(ll x,ll k){
    	ll res=1;
    	for(;k;k>>=1,x=x*x%P) if(k&1) res=res*x%P;
    	return res;
    }
    
    int Mod_Inv[N];
    int rev[N],w[N],iw[N],tmp[N];
    int PreMake(int n){
    	reg int R=1,cc=-1;
    	while(R<n) R<<=1,cc++;
    	rep(i,1,R-1) rev[i]=(rev[i>>1]>>1)|((i&1)<<cc);
    	return R;
    }
    
    void NTT(int n,int *a,int f){
    	rep(i,1,n-1) if(i<rev[i]) swap(a[i],a[rev[i]]);
    	if(f==1) {
    		for(reg int i=1;i<n;i<<=1) {
    			reg int len=(1<<20)/i;
    			for(int j=0,t=0;j<i;++j,t+=len) tmp[j]=w[t];
    			for(reg int l=0;l<n;l+=i*2) {
    				for(reg int j=l;j<l+i;j++) {
    					reg int t=1ll*a[j+i]*tmp[j-l]%P;
    					a[j+i]=a[j]-t,Mod2(a[j+i]);
    					a[j]+=t,Mod1(a[j]);
    				}
    			}
    		}
    	} else {
    		for(reg int i=1;i<n;i<<=1) {
    			reg int len=(1<<20)/i;
    			for(int j=0,t=0;j<i;++j,t+=len) tmp[j]=iw[t];
    			for(reg int l=0;l<n;l+=i*2) {
    				for(reg int j=l;j<l+i;j++) {
    					reg int t=1ll*a[j+i]*tmp[j-l]%P;
    					a[j+i]=a[j]-t,Mod2(a[j+i]);
    					a[j]+=t,Mod1(a[j]);
    				}
    			}
    		}
    		int base=Mod_Inv[n];
    		rep(i,0,n-1) a[i]=1ll*a[i]*base%P;
    	}
    }
    
    namespace Inv{
    	//F(x)G(x)=1
    	// G(x)^2+H(x)^2-2G(x)H(x)=0
    	// G(x)+H(x)^2*F(x)-2H(x)=0
    	// G(x)=2H(x)-H(x)^2*F(x)
    
    	int A[N];
    	void Inv(int *a,int *b,int n) {
    		int len=1;
    		b[0]=qpow(a[0],P-2);
    		for(len=2;;len<<=1) {
    			int R=PreMake(len<<1);
    			rep(i,0,len-1) A[i]=a[i];
    			rep(i,len,R-1) A[i]=b[i]=0;
    			NTT(R,A,1),NTT(R,b,1);
    			rep(i,0,R-1) b[i]=(2-1ll*b[i]*A[i]%P+P)*b[i]%P;
    			NTT(R,b,-1);
    			rep(i,len,R) b[i]=0;
    			if(len>=n) break;
    		}
    		rep(i,n,len) b[i]=0;
    	}
    }
    
    namespace Ln{
    	// G(x)=ln F(x);
    	// G'(x) = F'(x)/F(x)
    	int c[N],d[N];
    	void Ln(int *a,int *b,int n) {
    		rep(i,0,n) b[i]=c[i]=0;
    		rep(i,1,n-1) c[i-1]=1ll*i*a[i]%P;
    		Inv::Inv(a,b,n-1);
    		int R=PreMake(n<<1);
    		rep(i,n,R) c[i]=b[i]=0;
    
    		NTT(R,c,1),NTT(R,b,1);
    		rep(i,0,R-1) b[i]=1ll*b[i]*c[i]%P;
    		NTT(R,b,-1);
    		rep(i,n,R) b[i]=0;
    
    		drep(i,n-1,1) b[i]=1ll*b[i-1]*Mod_Inv[i]%P;
    		b[0]=0;
    	}
    }
    
    namespace Exp{
    	int c[N];
    	void Exp(int *a,int *b,int n){ 
    		b[0]=1;
    		int len;
    		for(len=2;;len<<=1) {
    			rep(i,0,len) c[i]=0;
    			Ln::Ln(b,c,len);
    			int R=PreMake(len<<1);
    			rep(i,0,len-1) {
    				c[i]=(!i)-c[i]+a[i];
    				Mod2(c[i]);
    			}
    			rep(i,len,R) c[i]=0;
    			NTT(R,b,1),NTT(R,c,1);
    			rep(i,0,R-1) b[i]=1ll*b[i]*c[i]%P;
    			NTT(R,b,-1);
    			rep(i,len,R) b[i]=0;
    			if(len>=n) break;
    		}
    		rep(i,n,len) b[i]=0;
    	}
    }
    
    int Fac[N],g[N],f[N];
    
    
    int main(){
    	n=1<<21;
    	w[0]=1,w[1]=qpow(3,(P-1)/n);
    	rep(i,2,n-1) w[i]=1ll*w[i-1]*w[1]%P;
    
    	iw[0]=1,iw[1]=qpow((P+1)/3,(P-1)/n);
    	rep(i,2,n-1) iw[i]=1ll*iw[i-1]*iw[1]%P;
    
    	Fac[0]=1;
    	rep(i,1,N-1) Fac[i]=1ll*Fac[i-1]*i%P;
    	Mod_Inv[1]=1;
    	rep(i,2,N-1) Mod_Inv[i]=1ll*(P-P/i)*Mod_Inv[P%i]%P;
    	n=rd();
    	f[1]=f[2]=1;
    	rep(i,3,n) {
    		f[i]=1ll*Fac[i]*(P+1)/2%P;
    		if(i%3) f[i]=(f[i]+1ll*Fac[i-1]*(P+1)/2)%P;
    	} // 预处理转移系数,注意还要额外除去阶乘
    	for(reg int i=1,t=1;i<=n;t=1ll*t*Mod_Inv[++i]%P) f[i]=1ll*f[i]*t%P;
    	Exp::Exp(f,g,n+1);
    	printf("%lld\n",1ll*g[n]*Fac[n]%P);
    }
    
    
    
    
    
  • 相关阅读:
    java实现获取当前年月日 小时 分钟 秒 毫秒
    四种常见的 POST 提交数据方式(application/x-www-form-urlencoded,multipart/form-data,application/json,text/xml)
    Cannot send, channel has already failed:
    Java 枚举(enum) 详解7种常见的用法
    C语言指针详解(经典,非常详细)
    ActiveMQ进阶配置
    Frame size of 257 MB larger than max allowed 100 MB
    SpringJMS解析--监听器
    SpringJMS解析-JmsTemplate
    delphi 修改代码补全的快捷键(由Ctrl+Space 改为 Ctrl + alt + Space)
  • 原文地址:https://www.cnblogs.com/chasedeath/p/12800773.html
Copyright © 2011-2022 走看看