• [题解] LuoguP4841 [集训队作业2013]城市规划


    Description

    (n)个点无重边、无自环、带标号的无向联通图个数,对(1004535809)((479 imes 2^{21} + 1))取模。(n le 130000)

    Solution

    模数好像是在提示了......这个模数非常适合(NTT)

    还是想题吧。首先问自己一个问题:不要求联通会不会?不会

    不连通的话最多有(inom{n}{2})条边,总方案数就是这些边选不选的问题,即(2^{inom{n}{2}})

    我们令不要求联通的(n)个点形成的简单无向图个数为(g_n),联通图个数为(f_n),不难发现有这个柿子

    [g_n = sumlimits_{i=1}^n inom{n-1}{i-1}f_ig_{n-i} ]

    意思是我枚举(1)号点所在联通块的大小,然后把这个联通快孤立起来,剩下的点随便连边。

    看到这个柿子想卷积?有组合数不方便卷,我们观察到

    [inom{n-1}{i-1} = frac{(n-1)!}{(n-i)!(i-1)!} ]

    不妨把两边同时乘(frac{1}{(n-1)!}),然后再把剩下的分母分配一下

    [frac{g_n}{(n-1)!} = sumlimits_{i=1}^{n}frac{f_i}{(i-1)!}frac{g_{n-i}}{(n-i)!} ]

    这个柿子就非常好做,我们令(h_n = frac{g_n}{(n-1)!}),然后用(frac{f_n}{(n-1)!})代替(f_n)(frac{g_n}{n!})代替(g_n),分别得到(h,f,g)的生成函数

    [H(x) = sumlimits_{n=0}^{infty} h_nx^n ]

    [F(x) = sumlimits_{n=0}^{infty} f_nx^n ]

    [G(x) = sumlimits_{n=0}^{infty} g_nx^n ]

    显然有

    [H(x) = F(x)G(x) ]

    因为答案只与(f_n)有关,我们可以放到(mod x^{n+1})下求(F(x))

    [F(x) equiv G^{-1}(x)H(x) (mod x^{n+1}) ]

    (G)求逆过后与(H)卷积,就求出了(F(x)),然后答案就是(f_n imes (n-1)!)

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int P=1004535809,g=3,ig=334845270,N=500010;
    inline int add(int x,int y){return x+y>=P?x+y-P:x+y;}
    inline int sub(int x,int y){return x-y<0?x-y+P:x-y;}
    inline int fpow(int x,int y){
    	int ret=1; for (x%=P;y;y>>=1,x=1ll*x*x%P)
    		if (y&1) ret=1ll*ret*x%P;
    	return ret;
    }
    namespace Poly{
    	int rev[N];
    	void init(int limit){
    		for (int i=0;i<limit;i++)
    			rev[i]=rev[i>>1]>>1|((i&1)?limit>>1:0);
    	}
    	void ntt(int *f,int n,int flg){
    		for (int i=0;i<n;i++) if (rev[i]<i) swap(f[i],f[rev[i]]);
    		for (int k=1,len=2;len<=n;len<<=1,k<<=1){
    			int wn=fpow(flg==1?g:ig,(P-1)/len);
    			for (int i=0;i<n;i+=len){
    				for (int w=1,j=i;j<i+k;j++,w=1ll*w*wn%P){
    					int tmp=1ll*w*f[j+k]%P;
    					f[j+k]=sub(f[j],tmp),f[j]=add(f[j],tmp);
    				}
    			}
    		}
    		if (flg==-1){
    			int inv=fpow(n,P-2);
    			for (int i=0;i<n;i++) f[i]=1ll*f[i]*inv%P;
    		}
    	}	
    	int F[N];
    	void getinv(int *f,int n,int *G){
    		if (n==1){G[0]=fpow(f[0],P-2);return;}
    		getinv(f,(n+1)>>1,G);
    		int limit=1; while(limit<=2*n)limit<<=1; init(limit);
    		for (int i=0;i<n;i++) F[i]=f[i];
    //		cout<<"wtf: "; for (int i=0;i<n;i++) cout<<G[i]<<" "; cout<<endl;
    		for (int i=n;i<limit;i++) F[i]=G[i]=0;
    		ntt(F,limit,1),ntt(G,limit,1);
    		for (int i=0;i<limit;i++) G[i]=1ll*G[i]*sub(2,1ll*F[i]*G[i]%P)%P;
    		ntt(G,limit,-1);
    		for (int i=n;i<limit;i++) G[i]=0;
    	}
    }
    using Poly::ntt;
    using Poly::getinv;
    int G[N],iG[N],H[N],F[N];
    int ifac[N],inv[N],fac[N];
    int main(){
    	int n; scanf("%d",&n);
    	fac[0]=fac[1]=ifac[0]=ifac[1]=1,inv[1]=1;
    	for (int i=2;i<=n;i++){
    		inv[i]=1ll*inv[P%i]*(P-P/i)%P;
    		ifac[i]=1ll*ifac[i-1]*inv[i]%P;
    		fac[i]=1ll*fac[i-1]*i%P;
    	}
    	G[0]=1;
    	for (int i=1;i<=n;i++) 
    		G[i]=1ll*fpow(2,1ll*i*(i-1)/2%(P-1))*ifac[i]%P,H[i]=1ll*G[i]*i%P;
    	getinv(G,n+1,iG);
    	int limit=1; while(limit<=2*n)limit<<=1; Poly::init(limit);
    	ntt(iG,limit,1),ntt(H,limit,1);
    	for (int i=0;i<limit;i++) F[i]=1ll*iG[i]*H[i]%P;
    	ntt(F,limit,-1);
    	printf("%d
    ",1ll*F[n]*fac[n-1]%P);
    	return 0;
    }
    
  • 相关阅读:
    面向对象编程(一)
    函数嵌套(闭包)、阶乘、斐波那数列知识
    函数的定义及用法
    常见例子
    Python解析JSON详解
    linux yum install mvn
    消息组件
    websphere 安装中出现JNDI资源找不到问题总结
    多业务Nginx解决方式
    python-pip 安装使用问题
  • 原文地址:https://www.cnblogs.com/wxq1229/p/12242965.html
Copyright © 2020-2023  润新知