[集訓隊作業2013]城市規劃

有標號簡單無向連通圖計數。

sol1

設 f(n) 表示 n 個點的簡單無向連通圖的個數, g(n) 表示 n 個點的簡單無向圖的個數。

考慮求出 g(n), 枚舉 1 所在連通塊的大小, 有:

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

多項式求逆即可。

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

sol2

不一定連通的圖就是連通圖的無序拼接。

\[\begin{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';
//	}
	
	++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;
}

)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章