• [BZOJ3456]城市规划


    [BZOJ3456]城市规划

    试题描述

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

    刚才说过, 阿狸的国家有 (n) 个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通. 为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案, 如果存在一个城市对, 在两个方案中是否建立路线不一样, 那么这两个方案就是不同的, 否则就是相同的. 现在你需要求出一共有多少不同的方案.

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

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

    输入

    仅一行一个整数 (n(le 130000))

    输出

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

    输入示例

    3
    

    输出示例

    4
    

    数据规模及约定

    对于 (100\%) 的数据, (n le 130000)

    题解

    (f(n)) 表示 (n) 个点的带标号简单无向连通图的个数,(g(n)) 表示 (n) 个点带标号简单无向图的个数,则显然有 (g(n) = 2^{C_n^2})

    (f(n)) 的计算是一个经典的容斥,它等于无向图个数减去不连通的个数,不连通图的个数可以通过枚举“和节点 (1) 在同一个连通块的点数”来计算,具体地:

    [f(n) = g(n) - sum_{i=1}^{n-1} C_{n-1}^{i-1} cdot f(i) cdot g(n-i) ]

    就是先确定哪 (i-1) 个点与 (1) 在同一个连通块中(组合数),然后连通部分的个数就是 (f(i)),剩下的部分随意连(即 (g(n-i)))。

    把组合数展开得到

    [f(n) = g(n) - sum_{i=1}^{n-1} frac{(n-1)!}{(i-1)!(n-i)!} cdot f(i) cdot g(n-i) \ f(n) = (n-1)! cdot left[ frac{g(n)}{(n-1)!} - sum_{i=1}^{n-1} frac{f(i)}{(i-1)!} cdot frac{g(n-i)}{(n-i)!} ight] \ frac{f(n)}{(n-1)!} = frac{g(n)}{(n-1)!} - sum_{i=1}^{n-1} frac{f(i)}{(i-1)!} cdot frac{g(n-i)}{(n-i)!} ]

    那么定义 (F(x), G(x), G_1(x)) 如下:

    [F(x) = sum_{i=1}^n frac{f(i)}{(i-1)!} x^i \ G(x) = sum_{i=1}^n frac{g(i)}{i!} x^i \ G_1(x) = sum_{i=1}^n frac{g(i)}{(i-1)!} x^i ]

    那么有

    [F(x) = G_1(x) - F(x) cdot G(x) \ F(x) = frac{G_1(x)}{G(x) + 1} ]

    最后输出时不要忘了把 ((n-1)!) 乘回来!

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    #define rep(i, s, t) for(int i = (s), mi = (t); i <= mi; i++)
    #define dwn(i, s, t) for(int i = (s), mi = (t); i >= mi; i--)
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 262144
    #define MOD 1004535809
    #define Groot 3
    #define LL long long
    
    int Pow(int a, int b) {
    	int ans = 1, t = a;
    	while(b) {
    		if(b & 1) ans = (LL)ans * t % MOD;
    		t = (LL)t * t % MOD; b >>= 1;
    	}
    	return ans;
    }
    int _Pow(int a, LL b) {
    	int ans = 1, t = a;
    	while(b) {
    		if(b & 1) ans = (LL)ans * t % MOD;
    		t = (LL)t * t % MOD; b >>= 1;
    	}
    	return ans;
    }
    
    int brev[maxn];
    void FFT(int *a, int len, int tp) {
    	int n = 1 << len;
    	rep(i, 0, n - 1) if(i < brev[i]) swap(a[i], a[brev[i]]);
    	rep(i, 1, len) {
    		int wn = Pow(Groot, MOD - 1 >> i);
    		if(tp < 0) wn = Pow(wn, MOD - 2);
    		for(int j = 0; j < n; j += 1 << i) {
    			int w = 1;
    			rep(k, 0, (1 << i >> 1) - 1) {
    				int la = a[j+k], ra = (LL)w * a[j+k+(1<<i>>1)] % MOD;
    				a[j+k] = (la + ra) % MOD;
    				a[j+k+(1<<i>>1)] = (la - ra + MOD) % MOD;
    				w = (LL)w * wn % MOD;
    			}
    		}
    	}
    	if(tp < 0) {
    		int invn = Pow(n, MOD - 2);
    		rep(i, 0, n - 1) a[i] = (LL)a[i] * invn % MOD;
    	}
    	return ;
    }
    
    void Mul(int *A, int *B, int n, int m, bool recover = 0) {
    	int N = 1, len = 0;
    	while(N <= n + m) N <<= 1, len++;
    	rep(i, 0, N - 1) brev[i] = (brev[i>>1] >> 1) | ((i & 1) << len >> 1);
    	FFT(A, len, 1); FFT(B, len, 1);
    	rep(i, 0, N - 1) A[i] = (LL)A[i] * B[i] % MOD;
    	FFT(A, len, -1); if(recover) FFT(B, len, -1);
    	return ;
    }
    
    int tmp[maxn];
    void inverse(int *f, int *g, int n) {
    	if(n == 1) return (void)(f[0] = Pow(g[0], MOD - 2));
    	inverse(f, g, n + 1 >> 1);
    	rep(i, 0, n - 1) tmp[i] = g[i];
    	int N = 1, len = 0;
    	while(N < (n << 1)) N <<= 1, len++;
    	rep(i, 0, N - 1) brev[i] = (brev[i>>1] >> 1) | ((i & 1) << len >> 1);
    	rep(i, n + 1 >> 1, N - 1) f[i] = 0;
    	rep(i, n, N - 1) tmp[i] = 0;
    	FFT(f, len, 1); FFT(tmp, len, 1);
    	rep(i, 0, N - 1) f[i] = ((LL)f[i] * (2ll - (LL)tmp[i] * f[i] % MOD) % MOD + MOD) % MOD;
    	FFT(f, len, -1);
    	return ;
    }
    
    int fac[maxn], ifac[maxn];
    void init(int n) {
    	ifac[1] = 1;
    	rep(i, 2, n) ifac[i] = (LL)(MOD - MOD / i) * ifac[MOD%i] % MOD;
    	fac[0] = ifac[0] = 1;
    	rep(i, 1, n) fac[i] = (LL)fac[i-1] * i % MOD, ifac[i] = (LL)ifac[i-1] * ifac[i] % MOD;
    	return ;
    }
    
    LL C2(int n) { return (LL)n * (n - 1) >> 1; }
    
    int G[maxn], G1[maxn], iG[maxn];
    
    int main() {
    	int n = read();
    	init(n);
    	
    	rep(i, 1, n) {
    		int t = _Pow(2, C2(i));
    		G[i] = (LL)t * ifac[i] % MOD;
    		G1[i] = (LL)t * ifac[i-1] % MOD;
    	}
    	G[0] = 1;
    	inverse(iG, G, n + 1);
    	Mul(G1, iG, n, n);
    	
    	printf("%lld
    ", (LL)G1[n] * fac[n-1] % MOD);
    	
    	return 0;
    }
    
  • 相关阅读:
    lr如何获取当前系统时间戳
    linux创建用户、设置密码、修改用户、删除用户
    Linux下安装load generator步骤及问题解决
    怎么将手动设定的IP变成固定的自动IP.
    Redis与Memcached的区别
    memcached 下载安装
    linux上传下载文件rz,sz
    oracle错误码
    sharepoint 2013 附件控件FileUpload怎样检验是否为图片的方法
    10gocm-&gt;session3-&gt;数据备份与恢复
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/8456318.html
Copyright © 2020-2023  润新知