1. 程式人生 > >【LG4841】城市規劃

【LG4841】城市規劃

規劃 聯通圖 ++ 組合數 swa int http 城市規劃 href

【LG4841】城市規劃

題面

洛谷

題解

\(t_i\)表示\(i\)個點的無向圖個數,顯然\(t_i=2^{C_i^2}\)

\(f_i\)表示\(i\)個點的無向連通圖個數,容斥一下,枚舉\(1\)號點所在連通塊的大小,再讓剩下的點隨便構成聯通圖,

則有:

\[ f_i=t_i-\sum_{j=1}^{i-1}f_j*C_{i-1}^{j-1}*t_{i-j} \]

展開組合數:

\[ f_i=t_i-\sum_{j=1}^{i-1}f_j*t_{i-j}*\frac {(i-1)!}{(i-j)!(j-1)!}\\Leftrightarrow \frac {f_i}{(i-1)!}=\frac {t_i}{(i-1)!}-\sum_{j=1}^{i-1}\frac {f_j}{(j-1)!}*\frac {t_{i-j}}{(i-j)!} \]

\(g_i=\frac {f_i}{(i-1)!},h_i=\frac {t_i}{i!}\),那麽

\[ g_i=i*h_i-\sum_{j=1}^{i-1}g_i*h_i \]

分治+\(NTT\)即可。

代碼

#include <iostream> 
#include <cstdio> 
#include <cstdlib> 
#include <cstring> 
#include <cmath> 
#include <algorithm> 
using namespace std; 
const int Mod = 1004535809;
int fpow(int x, int y) {
    int res = 1; 
    while (y) { 
        if (y & 1) res = 1ll * res * x % Mod; 
        x = 1ll * x * x % Mod; 
        y >>= 1; 
    } 
    return res; 
} 
const int G = 3, iG = fpow(G, Mod - 2); 
const int MAX_N = 4e5 + 5;

int Limit, rev[MAX_N]; 
void NTT(int *p, int op) { 
    for (int i = 0; i < Limit; i++) if (i < rev[i]) swap(p[i], p[rev[i]]); 
    for (int i = 1; i < Limit; i <<= 1) { 
        int rot = fpow(op == 1 ? G : iG, (Mod - 1) / (i << 1)); 
        for (int j = 0; j < Limit; j += (i << 1)) { 
            int w = 1; 
            for (int k = 0; k < i; k++, w = 1ll * w * rot % Mod) { 
                int x = p[j + k], y = 1ll * w * p[i + j + k] % Mod; 
                p[j + k] = (x + y) % Mod, p[i + j + k] = (x - y + Mod) % Mod; 
            } 
        } 
    }
    if (op == -1) { 
        int inv = fpow(Limit, Mod - 2); 
        for (int i = 0; i < Limit; i++) p[i] = 1ll * p[i] * inv % Mod; 
    } 
}

int g[MAX_N], h[MAX_N]; 
void Div(int l, int r) { 
    if (l == r) return ; 
    static int A[MAX_N], B[MAX_N], C[MAX_N]; 
    int mid = (l + r) >> 1;
    Div(l, mid);
    int p = 0; 
    for (Limit = 1; Limit <= (r - l) * 2; Limit <<= 1, ++p) ; 
    for (int i = 0; i < Limit; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (p - 1)); 
    for (int i = 0; i <= mid - l; i++) A[i] = g[i + l]; 
    for (int i = 0; i < r - l; i++) B[i] = h[i + 1];  
    for (int i = mid - l + 1; i < Limit; i++) A[i] = 0; 
    for (int i = r - l; i < Limit; i++) B[i] = 0; 
    NTT(A, 1); NTT(B, 1); 
    for (int i = 0; i < Limit; i++) C[i] = 1ll * A[i] * B[i] % Mod; 
    NTT(C, -1); 
    for (int i = mid + 1; i <= r; i++) g[i] = (g[i] - C[i - 1 - l] + Mod) % Mod; 
    Div(mid + 1, r); 
}
int N, fac[MAX_N], ifc[MAX_N]; 
int C(int n, int m) {
    if (m > n) return 0; 
    else return 1ll * fac[n] * ifc[m] % Mod * ifc[n - m] % Mod; 
} 
int main () { 
#ifndef ONLINE_JUDGE 
    freopen("cpp.in", "r", stdin); 
#endif 
    cin >> N; 
    fac[0] = 1; for (int i = 1; i <= N; i++) fac[i] = 1ll * fac[i - 1] * i % Mod; 
    ifc[N] = fpow(fac[N], Mod - 2); for (int i = N - 1; ~i; i--) ifc[i] = 1ll * ifc[i + 1] * (i + 1) % Mod; 
    for (int i = 1; i <= N; i++) h[i] = 1ll * fpow(2, 1ll * i * (i - 1) / 2 % (Mod - 1)) * ifc[i] % Mod; 
    for (int i = 1; i <= N; i++) g[i] = 1ll * ifc[i - 1] * fpow(2, 1ll * i * (i - 1) / 2 % (Mod - 1)) % Mod; 
    Div(1, N); 
    printf("%d\n", (int)(1ll * g[N] * fac[N - 1] % Mod)); 
    return 0; 
} 

【LG4841】城市規劃