• Tsinsen A1493 城市规划(DP + CDQ分治 + NTT)


    题目

    Source

    http://www.tsinsen.com/A1493

    Description

    刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了.
    刚才说过, 阿狸的国家有n个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通.
    为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案, 如果存在一个城市对, 在两个方案中是否建立路线不一样, 那么这两个方案就是不同的, 否则就是相同的. 现在你需要求出一共有多少不同的方案.
    好了, 这就是困扰阿狸的问题. 换句话说, 你需要求出n个点的简单(无重边无自环)无向连通图数目.
    由于这个数字可能非常大, 你只需要输出方案数mod 1004535809(479 * 2 ^ 21 + 1)即可.

    Input

    仅一行一个整数n(<=130000)

    Output

    仅一行一个整数, 为方案数 mod 1004535809.

    Sample Input

    3
    4
    100000

    Sample Output

    4
    38
    829847355

    分析

    楼教主男人八题也又一题是和这题一样,n个有标号点能构成的简单无向连通图数,不过这题题目数据大很多。做法如下:

    • 补集转化,设$f[n]$表示n个带标号的点能构成的简单图数,而只要利用$f[n]$减去不连通的数目就是要求的答案了。其中$f[n]=2^{n(n-1)/2}$,因为完全图有$n(n-1)/2$条边,对于每条边选或不选来构成一张简单图。
    • $dp[n]$表示n个带标号的点能构成的简单无向连通图数
    • 考虑通过固定一个点,枚举这个点所在连通块的大小来转移:$dp[n] = f[n]-sum_{i=1}^{n-1}C_{n-1}^{i-1}dp[i]f[n-i]$
    • 整理成卷积形式:$d[n] = f[n]-(n-1)!sum_{i=1}^{n-1}((i-1)!)^{-1}d[i] imes ((n-i)!)^{-1}f[n-i]$
    • 最后就是用分治FFT来做了。

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define MAXN 262144
    
    //const long long P=50000000001507329LL; // 190734863287 * 2 ^ 18 + 1
    const int P=1004535809; // 479 * 2 ^ 21 + 1
    //const int P=998244353; // 119 * 2 ^ 23 + 1
    const int G=3;
    
    long long mul(long long x,long long y){
    	return x*y%P;
    }
    long long qpow(long long x,long long k){
    	long long ret=1;
    	while(k){
    		if(k&1) ret=mul(ret,x);
    		k>>=1;
    		x=mul(x,x);
    	}
    	return ret;
    }
    
    long long wn[25];
    void getwn(){
    	for(int i=1; i<=21; ++i){
    		int t=1<<i;
    		wn[i]=qpow(G,(P-1)/t);
    	}
    }
    
    int len;
    void NTT(long long y[],int op){
    	for(int i=1,j=len>>1,k; i<len-1; ++i){
    		if(i<j) swap(y[i],y[j]);
    		k=len>>1;
    		while(j>=k){
    			j-=k;
    			k>>=1;
    		}
    		if(j<k) j+=k;
    	}
    	int id=0;
    	for(int h=2; h<=len; h<<=1) {
    		++id;
    		for(int i=0; i<len; i+=h){
    			long long w=1;
    			for(int j=i; j<i+(h>>1); ++j){
    				long long u=y[j],t=mul(y[j+h/2],w);
    				y[j]=u+t;
    				if(y[j]>=P) y[j]-=P;
    				y[j+h/2]=u-t+P;
    				if(y[j+h/2]>=P) y[j+h/2]-=P;
    				w=mul(w,wn[id]);
    			}
    		}
        }
        if(op==-1){
    		for(int i=1; i<len/2; ++i) swap(y[i],y[len-i]);
    		long long inv=qpow(len,P-2);
    		for(int i=0; i<len; ++i) y[i]=mul(y[i],inv);
        }
    }
    void Convolution(long long A[],long long B[],int n){
    	for(len=1; len<(n<<1); len<<=1);
    	for(int i=n; i<len; ++i){
    		A[i]=B[i]=0;
    	}
    
    	NTT(A,1); NTT(B,1);
    	for(int i=0; i<len; ++i){
    		A[i]=mul(A[i],B[i]);
    	}
    	NTT(A,-1);
    }
    
    long long A[MAXN],B[MAXN];
    
    long long d[MAXN],f[MAXN]={1},fact[MAXN]={1},fact_inv[MAXN]={1};
    /*
        d[n] = f[n]-fact[n-1]*Σ(fact_inv[i-1]*d[i]*f[n-i]*fact_inv[n-i])
    */
    void cdq(int l,int r){
        if(l==r) return;
        int mid=l+r>>1;
        cdq(l,mid);
        for(int i=l; i<=mid; ++i){
            A[i-l]=mul(fact_inv[i-1],d[i]);
        }
        for(int i=mid-l+1; i<=r-l; ++i) A[i]=0;
        for(int i=0; i<=r-l; ++i){
            B[i]=mul(fact_inv[i],f[i]);
        }
        Convolution(A,B,r-l+1);
        for(int i=mid+1; i<=r; ++i){
            d[i]-=mul(fact[i-1],A[i-l]);
            if(d[i]<0) d[i]+=P;
        }
        cdq(mid+1,r);
    }
    
    int main(){
    	getwn();
    	for(int i=1; i<=130000; ++i){
            fact[i]=mul(fact[i-1],i);
            fact_inv[i]=qpow(fact[i],P-2);
            d[i]=f[i]=qpow(2,(i-1LL)*i/2);
    	}
    	cdq(1,130000);
    	int n;
    	while(~scanf("%d",&n)){
            printf("%lld
    ",d[n]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Element节点
    Document节点
    ParentNode接口,ChildNode接口
    NodeList接口,HTMLCollection接口
    Node接口
    DOM概述
    Promise对象
    定时器
    IT常用日语
    配置JavaWeb开发环境
  • 原文地址:https://www.cnblogs.com/WABoss/p/5929692.html
Copyright © 2020-2023  润新知