zoukankan      html  css  js  c++  java
  • [集训队作业2013]城市规划

    有标号简单无向连通图计数。

    sol1

    设 f(n) 表示 n 个点的简单无向连通图的个数, g(n) 表示 n 个点的简单无向图的个数。

    考虑求出 g(n), 枚举 1 所在连通块的大小, 有:

    [egin{align} g(n) &= sum_{i=1}^{n}inom{n-1}{i-1}f(i)g(n-i)\ &= sum_{i=0}^{n-1}inom{n-1}{i}f(i+1)g(n-1-i)\ end{align} ]

    多项式求逆即可。

    具体地, (hat {lhd G(z)} = hat G(z)cdothat{lhd F(z)})(hat{lhd F(z)} = hat G(z)^{-1}cdot hat{lhd G(z)})

    sol2

    不一定连通的图就是连通图的无序拼接。

    [egin{align} G(z) &= sum_{n} frac{F(z)^n}{n!}z^n\ &= e^{F(z)} end{align} ]

    所以 (F(z) = ln G(z))

    #include<bits/stdc++.h>
    typedef long long LL;
    using namespace std;
    
    const int N = 8e5 + 23, mo = 1004535809;
    LL ksm(LL a, LL b) {
    	LL res = 1ll;
    	for(; b; b>>=1, a=a*a%mo)
    		if(b & 1) res = res * a % mo;
    	return res;
    }
    const LL g = 3ll, ig = ksm(g, mo - 2);
    
    void Dervt(int n, LL *a, LL *b) {
    	for(int i = 1; i < n; ++i) b[i - 1] = a[i] * (LL)i % mo;
    	b[n - 1] = 0ll;
    } 
    
    void Integ(int n, LL *a, LL *b) {
    	for(int i = 1; i < n; ++i) b[i] = a[i - 1] * ksm(i, mo - 2) % mo;
    	b[0] = 0ll;
    }
    
    int rv[N];
    LL t[N];
    void ntt_init(int n) {
    	for(int i = 1; i < n; ++i) rv[i] = (rv[i>>1]>>1) | (i&1 ? n>>1 : 0);
    }
    void ntt(LL *a, int n, int type) {
    	for(int i = 1; i < n; ++i) if(i < rv[i]) swap(a[i], a[rv[i]]);
    	for(int m = 2; m <= n; m = m<<1) {
    		LL w = ksm(type == 1 ? g : ig, (mo - 1) / m);
    		for(int i = 0; i < n; i = i + m) {
    			LL tmp = 1ll;
    			for(int j = 0; j < (m>>1); ++j) {
    				LL p = a[i+j], q = a[i+j+(m>>1)] * tmp % mo;
    				a[i+j] = (p+q) % mo, a[i+j+(m>>1)] = (p-q+mo) % mo;
    				tmp = tmp * w % mo;
    			}
    		}
    	}
    	if(type == -1) {
    		LL Inv = ksm(n, mo - 2);
    		for(int i = 0; i < n; ++i) a[i] = a[i] * Inv % mo;
    	}
    }
    
    void poly_inv(int deg, LL *a, LL *b) {
    	if(deg == 1) { b[0] = ksm(a[0], mo - 2); return; }
    	poly_inv((deg + 1) >> 1, a, b);
    	int len = 1; while(len < (deg << 1)) len = len << 1;
    	ntt_init(len);
    	for(int i = 0; i < deg; ++i) t[i] = a[i];
    	for(int i = deg; i < len; ++i) t[i] = b[i] = 0ll;
    	ntt(b, len, 1), ntt(t, len, 1);
    	for(int i = 0; i < len; ++i) b[i] = b[i] * (2ll - t[i] * b[i] % mo) % mo;
    	ntt(b, len, -1);
    	for(int i = deg; i < len; ++i) b[i] = 0ll;
    }
    
    LL b[N], c[N];
    void poly_ln(int deg, LL *a) {
    	poly_inv(deg, a, b), Dervt(deg, a, c);
    	int len = 1; while(len < (deg << 1)) len = len << 1;
    	ntt_init(len);
    	for(int i = deg; i < len; ++i) b[i] = c[i] = 0ll;
    	ntt(b, len, 1), ntt(c, len, 1);
    	for(int i = 0; i < len; ++i) b[i] = b[i] * c[i] % mo;
    	ntt(b, len, -1);
    	Integ(deg, b, a);
    }
    
    
    LL fac[N], ifac[N];
    int n;
    LL G[N], F[N];
    
    int main()
    {
    	scanf("%d", &n);
    	if(n == 0) {
    		puts("0");
    		return 0;
    	}
    	fac[0] = 1ll;
    	for(int i = 1; i <= n; ++i) fac[i] = fac[i-1] * (LL)i % mo;
    	ifac[n] = ksm(fac[n], mo - 2);
    	for(int i = n; i > 0; --i) ifac[i-1] = ifac[i] * (LL)i % mo;
    	
    //	for(int i = 0; i <= n; ++i) {
    //		cout << fac[i] << ' ' << fac[i] * ifac[i] % mo << '
    ';
    //	}
    	
    	++n;
    	for(int i = 0; i < n; ++i) G[i] = ksm(2, (LL)i * (LL)(i-1ll) / 2ll) * ifac[i] % mo;
    	poly_ln(n, G);
    	--n;
    	cout << G[n] * fac[n] % mo;
    	return 0;
    }
    

    )

  • 相关阅读:
    JS函数强化
    Javascript创建对象的方式
    call和apply的区别
    事件绑定和普通事件有什么区别
    又走一个
    风的季节
    关于Dictionary的线程安全问题
    进程管理简述
    开通
    WPF 音乐播放器界面
  • 原文地址:https://www.cnblogs.com/tztqwq/p/14350170.html
Copyright © 2011-2022 走看看