• 【LG4841】城市规划


    【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
    ", (int)(1ll * g[N] * fac[N - 1] % Mod)); 
        return 0; 
    } 
    
  • 相关阅读:
    《免费:商业的未来》书摘
    wxWidgets的安装编译、相关配置、问题分析处理
    CodeBlocks的下载安装、配置、简单编程
    【最新】让快捷方式 实现相对路径——非.bat方式实现
    跨平台C/C++集成开发环境-Code::Blocks-内置GCC
    IOS自定义alertview
    IOS快速开发之常量定义
    为UITableViewController瘦身
    IOS中扩展机制Category和associative
    IOS制作一个漂亮的登录界面
  • 原文地址:https://www.cnblogs.com/heyujun/p/10360151.html
Copyright © 2020-2023  润新知