Description:
刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了.
刚才说过, 阿狸的国家有n 个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通.
为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案, 如果存在一个城市对, 在两个方案中是否建立路线不一样, 那么这两个方案就是不同的, 否则就是相同的. 现在你需要求出一共有多少不同的方案.
好了, 这就是困扰阿狸的问题. 换句话说, 你需要求出n 个点的简单(无重边无自环)无向连通图数目.
由于这个数字可能非常大, 你只需要输出方案数mod 1004535809(479 * 2 ^21 + 1)即可.
n <= 130000
题解:
这个动态规划的关键在于确立一个标号,枚举它所在的连通块。
设fi表示答案。
多项式求逆:
fn=2C2n−∑n−1i=1Ci−1n−1∗fi∗2C2n−i
2C2n=fn+∑n−1i=1Ci−1n−1∗fi∗2C2n−i
2C2n=∑ni=1Ci−1n−1∗fi∗2C2n−i
2C2n/(n−1)!=∑ni=1fi/(i−1)!∗2C2n−i/(n−i)!
设Fn=2C2n/(n−1)!,Gi=fi/(i−1)!,Hi=2C2i/(i)!
显然有F=G∗H,G=F∗H−1
于是对H进行多项式求逆,搞一下就能求出F,进而推出f。
分治:
fn=2C2n−∑n−1i=1Ci−1n−1∗fi∗2C2n−i
fn=2C2n−(n−1)!∑n−1i=1fi/(i−1)!∗2C2n−i/(n−i)!
用cdq分治的思想。
Solve(x,y)
设m=x+y>>1
先Solve(x,m)
这样就求出了f(x..m)
看作多项式乘上另一个多项式,再把得出的结果一一加给m+1..y,继续分治。
Code(多项式求逆):
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define ff(i, x, y) for(int i = x; i < y; i ++)
#define fd(i, x, y) for(int i = x; i >= y; i --)
using namespace std;
const ll mo = 1004535809;
const int N = 130005 * 4;
int n, m, tp, tx;
ll a[N], b[N], b1[N], b2[N], c[N], fac[N], nf[N], w[N];
ll ksm(ll x, ll y) {
ll s = 1;
for(; y; y >>= 1, x = x * x % mo)
if(y & 1) s = s * x % mo;
return s;
}
void dft(ll *a, int n) {
ff(i, 0, n) {
int p = i, q = 0;
fo(j, 1, tx) q = q * 2 + p % 2, p /= 2;
if(q > i) swap(a[q], a[i]);
}
for(int m = 2; m <= n; m *= 2) {
int h = m / 2;
ff(i, 0, h) {
ll W = w[i * (n / m)];
for(int j = i; j < n; j += m) {
int k = j + h;
ll u = a[j], v = a[k] * W % mo;
a[j] = (u + v) % mo; a[k] = (u - v + mo) % mo;
}
}
}
}
void fft(ll *a, ll *b, int n) {
ll v = ksm(3, (mo - 1) / n); w[0] = 1;
fo(i, 1, n) w[i] = w[i - 1] * v % mo;
dft(a, n); dft(b, n); ff(i, 0, n) a[i] = a[i] * b[i] % mo;
fo(i, 0, n / 2) swap(w[i], w[n - i]);
dft(a, n); v = ksm(n, mo - 2);
ff(i, 0, n) a[i] = a[i] * v % mo;
}
int main() {
scanf("%d", &n); while(1 << ++ tp <= n);
fac[0] = 1; fo(i, 1, n) fac[i] = fac[i - 1] * i % mo;
nf[n] = ksm(fac[n], mo - 2); fd(i, n - 1, 0) nf[i] = nf[i + 1] * (i + 1) % mo;
fo(i, 0, n) c[i] = ksm(2, (ll) i * (i - 1) / 2) * nf[i];
fo(i, 1, n) a[i] = ksm(2, (ll) i * (i - 1) / 2) * nf[i - 1];
b[0] = ksm(c[0], mo - 2);
fo(ii, 1, tp) {
m = 1 << ii;
memcpy(b1, b, sizeof b); memcpy(b2, b, sizeof b);
memset(b, 0, sizeof b);
tx = ii + 1;
ff(j, 0, m) b[j] = c[j];
fft(b, b1, m * 2);
ff(i, m, m * 2) b[i] = 0;
ff(i, 0, m) b[i] = (mo - b[i]) % mo; b[0] = (b[0] + 2) % mo;
fft(b, b2, m * 2);
ff(i, m, m * 2) b[i] = 0;
}
fft(a, b, 1 << tx);
ll ans = a[n] * fac[n - 1] % mo;
printf("%lld", ans);
}