zoukankan      html  css  js  c++  java
  • Luogu 4841 城市规划

    BZOJ 3456 权限题

    太菜了推不出式子

    我们设$f(n)$表示$n$个点的无向连通图的数量,那么有

    $$f(n) = 2^{inom{n}{2}} - sum_{i = 1}^{n - 1}inom{n - 1}{i - 1}f(i)2^{inom{n - i}{2}}$$

    思路就是全部减去不合法的,枚举$1$号点所在的联通块的大小,剩下随便生成一张无向图。

    拆开组合数,简单变形一下

    $$f(n) = 2^{inom{n}{2}} - (n - 1)!sum_{i = 1}^{n - 1}frac{2^{inom{n - i}{2}}}{(n - i)!}frac{f(i)}{(i - 1)!}$$

    记$h(i) = frac{f(i)}{(i - 1)!}$,$g(i) = frac{2^{inom{i}{2}}}{i!}$

    $$(n - 1)!h(n) = 2^{inom{n}{2}} - (n - 1)!sum_{i = 1}^{n - 1}g(i)h(n - i)$$

    发现这个式子可以用分治FFT优化,直接上就做完了。

    时间复杂度$O(nlog^2n)$。

    Code:

    #include <cstdio>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    
    const int N = 3e5 + 5;
    const ll P = 1004535809LL;
    
    int n, lim, pos[N];
    ll f[N], g[N], fac[N], inv[N], a[N], b[N];
    
    template <typename T>
    inline void read(T &X) {
        X = 0; char ch = 0; T op = 1;
        for (; ch > '9'|| ch < '0'; ch = getchar())
            if (ch == '-') op = -1;
        for (; ch >= '0' && ch <= '9'; ch = getchar())
            X = (X << 3) + (X << 1) + ch - 48;
        X *= op;
    }
     
    inline ll fpow(ll x, ll y) {
        ll res = 1;
        for (; y > 0; y >>= 1) {
            if (y & 1) res = res * x % P;
            x = x * x % P;
        }
        return res;
    }
    
    template <typename T>
    inline void swap(T &x, T &y) {
        T t = x; x = y; y = t;
    }
    
    inline void prework(int len) {
        int l = 0;
        for (lim = 1; lim <= len; lim <<= 1, ++l);
        for (int i = 0; i < lim; i++)
            pos[i] = (pos[i >> 1] >> 1) | ((i & 1) << (l - 1));
    } 
    
    inline void ntt(ll *c, int opt) {
        for (int i = 0; i < lim; i++)    
            if (i < pos[i]) swap(c[i], c[pos[i]]);
        for (int i = 1; i < lim; i <<= 1) {
            ll wn = fpow(3, (P - 1) / (i << 1));
            if (opt == -1) wn = fpow(wn, P - 2);
            for (int len = i << 1, j = 0; j < lim; j += len) {
                ll w = 1;
                for (int k = 0; k < i; k++, w = w * wn % P) {
                    ll x = c[j + k], y = w * c[j + k + i] % P;
                    c[j + k] = (x + y) % P, c[j + k + i] = (x - y + P) % P;
                }
            }
        }
        
        if (opt == -1) {
            ll invP = fpow(lim, P - 2);
            for (int i = 0; i < lim; i++) c[i] = c[i] * invP % P;
        }
    }
    
    inline ll getC(int x) {
        if (x < 2) return 0;
        return (1LL * x * (x - 1) / 2);
    }
    
    void solve(int l, int r) {
        if (l == r) {
            f[l] = (fpow(2, getC(l) % (P - 1)) - f[l] * fac[l - 1] % P + P) % P;
            f[l] = f[l] * inv[l - 1] % P;
            return;
        }
        
        int mid = ((l + r) >> 1);
        solve(l, mid);
        
        prework(r - l + 1);
        for (int i = 0; i < lim; i++) a[i] = b[i] = 0LL;
        for (int i = l; i <= mid; i++) a[i - l] = f[i];
        for (int i = 1; i <= r - l; i++) b[i - 1] = g[i];
        ntt(a, 1), ntt(b, 1);
        for (int i = 0; i < lim; i++) a[i] = a[i] * b[i] % P;
        ntt(a, -1);
        
        for (int i = mid + 1; i <= r; i++)
            f[i] = (f[i] + a[i - l - 1] % P) % P;
        
        solve(mid + 1, r);
    }
    
    int main() {
        read(n);
        
        fac[0] = 1LL;
        for (int i = 1; i <= n; i++) fac[i] = fac[i - 1] * i % P;
        inv[n] = fpow(fac[n], P - 2);
        for (int i = n - 1; i >= 0; i--) inv[i] = inv[i + 1] * (i + 1) % P;
        
        for (int i = 1; i <= n; i++) 
            g[i] = fpow(2LL, getC(i) % (P - 1)) * inv[i] % P;
        
        solve(1, n);
        
        printf("%lld
    ", f[n] * fac[n - 1] % P);
        return 0;
    }
    View Code
  • 相关阅读:
    VBA基础一:对象、属性、方法、变量
    js画吊线图
    C++读取硬盘物理序列号-非管理员权限
    什么是句柄?
    2020年WIN7系统的几个问题处理
    静态分析:IDA逆向代码段说明 text、idata、rdata、data
    入门级汇编语法句读
    Ollydbg 单步跟踪F8
    IDA使用之旅(四)
    CSP认证201409-1-相邻数对-(Java)100分
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/10200437.html
Copyright © 2011-2022 走看看