[BZOJ3456]城市规划

Posted xjr_01

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ3456]城市规划相关的知识,希望对你有一定的参考价值。

[BZOJ3456]城市规划

试题描述

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

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

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

由于这个数字可能非常大, 你只需要输出方案数 \(\mod 1004535809(479 \times 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)!} \right] \\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\n", (LL)G1[n] * fac[n-1] % MOD);
    
    return 0;
}

以上是关于[BZOJ3456]城市规划的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ3456:城市规划——题解

bzoj3456 城市规划

BZOJ 3456: 城市规划

[BZOJ3456]城市规划

bzoj 3456城市规划

BZOJ3456 城市规划 分治NTT