• Jzoj3303 城市规划


    刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了.

    刚才说过, 阿狸的国家有n 个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通.

    为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案, 如果存在一个城市对, 在两个方案中是否建立路线不一样, 那么这两个方案就是不同的, 否则就是相同的. 现在你需要求出一共有多少不同的方案.

    好了, 这就是困扰阿狸的问题. 换句话说, 你需要求出n 个点的简单(无重边无自环)无向连通图数目.

    由于这个数字可能非常大, 你只需要输出方案数mod 1004535809(479 * 2 ^21 + 1)即可.

    NTT第一道例题

    我们令f[k]表示n个点的图的无向图个数,显然f[k]=2^C(k,2)

    令g[k]表示k个点的无向连通图个数,用dp计算就得到g[k]=f[k]-ΣC(k-1,i-1)*g[i]*f[k-i] (1<=i<k)

    g[k]=f[k]-(k-1)!Σg[i]/(i-1)!*f[k-i]/(k-i)!

    g[k]=f[k]-(k-1)!Σg'[i]*f'[k-i]

    发现不能直接做,我们考虑用分治,计算g[l..m]对g[m+1,r]的贡献,这样一次就是O(n lg n)的

    总复杂度O(n lg^2 n)

    #pragma GCC optimize("O3")
    #pragma G++ optimize("O3")
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define N 280010
    #define Rg register
    #define LL long long
    #define M 1004535809
    using namespace std;
    int n,nL,m,a[N],b[N],z[N];
    LL f[N],g[N],js[N],inv[N],W[N],iW[N];
    inline int p2(int x,int t=1){
    	for(;t<x;t<<=1); return t<<1;
    }
    inline int lg(int x,int t=0){
    	for(;x>1;x>>=1) ++t; return t;
    }
    inline int pow(LL x,LL k,LL& s){
    	for(s=1;k;x=x*x%M,k>>=1) k&1?s=s*x%M:0;
    }
    void NTT(int* a,int* b,int n,int g){
    	for(int i=0,j,k,t;i<n;++i){
    		for(j=0,k=i,t=n-1;t;t>>=1,k>>=1) j=(j<<1)|(k&1);
    		b[j]=a[i];
    	}
    	for(int m=2;m<=n;m<<=1){
    		Rg LL w=g?W[m]:iW[m],u,v,z;
    		for(Rg int i,k=m>>1,j=0;j<n;j+=m)
    			for(z=1,i=0;i<k;++i,z=z*w%M){
    				u=b[i+j]; v=z*b[i+j+k]%M;
    				b[i+j]=(u+v)%M; b[i+j+k]=(u-v+M)%M;
    			}
    	}
    	memcpy(a,b,n<<2);
    }
    void MUL(int l,int r,int m){
    	LL iv; int n=p2(m-l+1);
    	memset(a,0,n<<2);
    	memset(b,0,n<<2);
    	for(int i=1;i<=r-l+1;++i)
    		a[i]=g[i+l-1]*inv[i+l-2]%M;
    	for(int i=1;i<=m-l;++i)
    		b[i]=f[i]*inv[i]%M;
    	NTT(a,z,n,1); NTT(b,z,n,1);
    	for(int i=0;i<n;++i) a[i]=(LL)a[i]*b[i]%M;
    	NTT(a,z,n,0); pow(n,M-2,iv);
    	for(int i=0;i<n;++i) a[i]=(LL)a[i]*iv%M;
    }
    void cdq(int l,int r){
    	if(l==r) g[l]=(f[l]-g[l]*js[l-1]%M+M)%M;
    	else{
    		int m=l+r>>1;
    		cdq(l,m);
    		MUL(l,m,r);
    		for(int i=m+1;i<=r;++i) g[i]=(g[i]+a[i-l+1])%M;
    		cdq(m+1,r);
    	}
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=*js=*inv=1;i<=n;++i) js[i]=js[i-1]*i%M;
    	pow(js[n],M-2,inv[n]); for(int i=n;i;--i) inv[i-1]=inv[i]*i%M;
    	for(int i=1;i<=n;++i) pow(2,i*(i-1ll)>>1,f[i]);
    	for(int j=1;j<=N;j<<=1){
    		pow(3,(M-1)/j,W[j]); pow(W[j],M-2,iW[j]);
    	}
    	cdq(1,p2(n)>>1); 
    	printf("%lld
    ",g[n]);
    }

  • 相关阅读:
    css基础教程
    网页加载-上下幕布分开
    Vue-Aixos
    webpack学习
    Vue、Element 路由跳转,左侧菜单高亮显示,页面刷新不会改变当前高亮菜单
    Vue知识概括
    JSON.parse() 与 JSON.stringify()
    Bootstrap4 样式笔记
    ES6基础语法
    V-model 双向绑定的原理是什么?
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/8449235.html
Copyright © 2020-2023  润新知