zoukankan      html  css  js  c++  java
  • bzoj3456城市规划 多项式取模

    題目大意

    求出有n个点的有标号简单连通无向图的数目。

    题解

    什么破玩意,直接输出(2^{C_n^2})走人
    我们发现这张图要求连通,而上式肯定不能保证连通。
    其实上式表示的是不保证连通的有标号简单无向图。
    就差在一个连通上啊。
    所以我们设(f(x))表示有x个点的有标号简单连通无向图的数目。
    然后设(g(x))为上式,即不保证连通时的方案数
    于是我们枚举节点1所在的连通块的大小,有

    [g(n) = sum_{i=1}^nC_{n-1}^{i-1}f(i)g(n-1) ]

    [frac{g(n)}{(n-1)!} = frac{sum_{i=1}^nC_{n-1}^{i-1}f(i)g(n-1)}{(n-1)!} ]

    [frac{2^{C_n^2}}{(n-1)!} = sum_{i=1}{n}frac{f(i)}{(i-1)!}frac{2^{C_{n-i}^2}}{(n-i)!} ]

    那么我们分别设它们的生成函数为

    [A(x) = sum_{n=1}^{infty}frac{f(n)}{(n-1)!}x^n ]

    [B(x) = sum_{n=0}^{infty}frac{2^{C_n^2}}{n!}x^n ]

    [C(x) = sum_{n=0}^{infty}frac{2^{C_n^2}}{(n-1)!}x^n ]

    所以我们有

    [C(x) = A(x)B(x) ]

    那么有

    [A(x) equiv B^{-1}(x)C(x) (mod ext{ }x^{n+1}) ]

    所以利用FFT算逆元,处理乘法即可.
    //这里用的FNT,即快速数论变换.

    #include <cmath>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    inline void read(int &x){
        x=0;char ch;bool flag = false;
        while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
        while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
    }
    const int maxn = 1 << 18;
    const int mod = 1004535809;
    const int pri_rt = 3;
    inline int qpow(int x,int p){
        int ret = 1;
        for(;p;x=1LL*x*x%mod,p>>=1) if(p&1) ret=1LL*ret*x%mod;
        return ret;
    }
    int len;
    int e[maxn],ie[maxn];
    inline int check(int &x){
        if(x < 0) x += mod;
        if(x >= mod) x -= mod;
    }
    inline void init(){
        int bas = qpow(pri_rt,(mod-1)/len);
        int inv = qpow(bas,mod-2);
        e[0] = ie[0] = 1;
        for(int i=1;i<len;++i){
            e[i] = 1LL*e[i-1]*bas % mod;
            ie[i] = 1LL*ie[i-1]*inv % mod;
        }
    }
    void FNT(int n,int *x,int *w){
        for(int i=0,t=0;i<n;++i){
            if(i > t) swap(x[i],x[t]);
            for(int j=n>>1;(t^=j) < j;j>>=1);
        }
        for(int m=2;m<=n;m<<=1){
            int k = m>>1,wn = len/m;
            for(int i=0;i<n;i+=m){
                for(int j=0,p=0;j<k;++j,p+=wn){
                    int u = 1LL*x[i+j+k]*w[p] % mod;
                    x[i+j+k] = x[i+j] - u;check(x[i+j+k]);
                    x[i+j] = x[i+j] + u;check(x[i+j]);
                }
            }
        }
        if(w == ie){
            int inv = qpow(n,mod-2);
            for(int i=0;i<n;++i) x[i] = 1LL*x[i]*inv%mod;
        }
    }
    struct Node{
        int n;
        int x[maxn];
        Node(){n = x[0] = 0;}
    };
    void get_inv(int n,const Node &A,Node &B){
        if(n == 1){
            B.n = 1;
            B.x[0] = qpow(A.x[0],mod-2);
            return;
        }
        static int X[maxn];
        get_inv((n+1)>>1,A,B);
        int p = 1;for(;p < n<<1 ;p<<=1);
        copy(A.x,A.x+n,X);fill(X+n,X+p,0);
        fill(B.x+B.n,B.x+p,0);
        FNT(p,X,e);FNT(p,B.x,e);
        for(int i=0;i<p;++i) B.x[i] = 1LL*B.x[i]*(2 - 1LL*X[i]*B.x[i] % mod) % mod;
        FNT(p,B.x,ie);B.n = n;
    }
    Node A,B,C;
    int inv[maxn],inv_fac[maxn],c[maxn];
    int main(){
        int n;read(n);
        int p;for(p=1;p<(n+1)<<1;p<<=1);
        len = p;init();
        inv[1] = inv_fac[0] = 1;
        for(int i=1;i<=n;++i){
            if(i != 1) inv[i] = -mod/i*(ll)inv[mod % i] % mod;
            if(inv[i] < 0) inv[i] += mod;
            inv_fac[i] = (ll)inv_fac[i-1]*inv[i]%mod;
        }
        c[0] = c[1] = 1;
        for(int i=2;i<=n;++i) c[i] = qpow(2,(ll)i*(i-1)/2 % (mod - 1));
        A.n = B.n = n+1;
        for(int i=0;i<=n;++i) A.x[i] = (ll)c[i]*inv_fac[i] % mod;
        for(int i=1;i<=n;++i) B.x[i] = (ll)c[i]*inv_fac[i-1]%mod;
        get_inv(n+1,A,C);
        fill(C.x + C.n,C.x + p,0);
        FNT(p,C.x,e);FNT(p,B.x,e);
        for(int i=0;i<=p;++i) C.x[i] = (ll)C.x[i]*B.x[i] % mod;
        FNT(p,C.x,ie);
        int ans = (ll)C.x[n]*qpow(inv_fac[n-1],mod - 2) % mod;
        if(ans < 0) ans += mod;
        printf("%d
    ",ans);
        getchar();getchar();
        return 0;
    }
    
  • 相关阅读:
    linux中~和/的区别
    Linux centos 7安装
    xshell远程连接虚拟机
    虚拟机Linux不能上网简单有效的解决办法
    visudo
    users
    TreeSizeFree(硬盘文件整理)
    dos2unix
    iconv
    PS1系统变量
  • 原文地址:https://www.cnblogs.com/Skyminer/p/6393825.html
Copyright © 2011-2022 走看看