zoukankan      html  css  js  c++  java
  • 【bzoj3456】城市规划 【FFT/NTT】【多项式求逆】

    题目大意:你需要求出n个点的简单(无重边无自环)无向连通图的数目模1004535809。n130000
    题解:我们令fn表示n个点的简单无向图的数目,gn表示n个点的简单无向连通图的数目。
    易得fn=2Cn2,意思是任意两点之间的边都可以取或不取。
    同时,fn=i=1nCn1i1gifni,意思是枚举点1所在连通块的大小i,从n-1个点里再选i-1个,连边组成一个联通块,剩下n-i个点随意连边。
    我们变一下这个式子。
    2Cn2=i=1nCn1i1gi2Cni2
    =>2Cn2=i=1n(n1)!(i1)!(ni)!gi2Cni2
    =>2Cn2=(n1)!i=1n(1(i1)!gi)(1(ni)!2Cni2)
    =>2Cn2(n1)!=i=1n(gi(i1)!)(2Cni2(ni)!)
    可以发现这是一个卷积的形式。
    我们令
    A(x)=i=1n2Ci2(i1)!xi
    B(x)=i=1ngi(i1)!xi
    C(x)=i=0n12Ci2i!xi
    A(x)B(x)×C(x)
    =>B(x)A(x)C1(x)(mod xn+1)
    因此我们可以通过多项式求逆和多项式乘法得到B。
    多项式求逆的关键公式:
    A(x)B(x)1(mod xn)
    A(x)B(x)10(mod xn)
    (A(x)B(x)1)20(mod x2n)
    A(x)(2B(x)B(x)2A(x))1(mod x2n)
    最后的答案为B[n](n1)!
    代码

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=270005;
    const ll mod=1004535809;
    int n,m,rev[N];
    ll jc[N],a[N],b[N],c[N],d[N];
    ll fastpow(ll a,ll x){
        a%=mod;
        ll res=1;
        while(x){
            if(x&1){
                res=res*a%mod;
            }
            x>>=1;
            a=a*a%mod;
        }
        return res;
    }
    ll getinv(ll a){
        return fastpow(a,mod-2);
    }
    void ntt(ll *a,int n,int dft){
        for(int i=0;i<n;i++){
            rev[i]=(rev[i>>1]>>1)|((i&1)*(n>>1));
            if(i<rev[i]){
                swap(a[i],a[rev[i]]);
            }
        }
        for(int i=1;i<n;i<<=1){
            ll wn=fastpow(3,(mod-1)/i/2);
            if(dft==-1){
                wn=getinv(wn);
            }
            for(int j=0;j<n;j+=i<<1){
                ll w=1,x,y;
                for(int k=j;k<j+i;k++,w=w*wn%mod){
                    x=a[k];
                    y=w*a[k+i]%mod;
                    a[k]=(x+y)%mod;
                    a[k+i]=(x-y+mod)%mod;
                }
            }
        }
        if(dft==-1){
            ll inv=getinv(n);
            for(int i=0;i<n;i++){
                a[i]=a[i]*inv%mod;
            }
        }
    }
    int main(){
        scanf("%d",&m);
        jc[0]=1;
        for(int i=1;i<=m;i++){
            jc[i]=jc[i-1]*i%mod;
        }
        for(n=1;n<=m;n<<=1);
        a[0]=1;
        for(int i=1;i<m;i++){
            a[i]=fastpow(2,1LL*i*(i-1)/2)*getinv(jc[i]);
        }
        b[0]=getinv(a[0]);
        for(int k=2;k<=n;k<<=1){
            for(int i=0;i<k;i++){
                c[i]=a[i];
                if(i<(k>>1)){
                    d[i]=b[i];
                }else{
                    d[i]=0;
                }
            }
            ntt(c,k<<1,1);
            ntt(d,k<<1,1);
            for(int i=0;i<(k<<1);i++){
                c[i]=(2*d[i]%mod-d[i]*d[i]%mod*c[i]%mod+mod)%mod;
            }
            ntt(c,k<<1,-1);
            ntt(d,k<<1,-1);
            for(int i=0;i<k;i++){
                b[i]=c[i];
            }
        }
        a[0]=0;
        for(int i=1;i<=m;i++){
            a[i]=fastpow(2,1LL*i*(i-1)/2)*getinv(jc[i-1]);
        }
        ntt(a,n<<1,1);
        ntt(b,n<<1,1);
        for(int i=0;i<(n<<1);i++){
            a[i]=a[i]*b[i]%mod;
        }
        ntt(a,n<<1,-1);
        printf("%lld
    ",a[m]*jc[m-1]%mod);
        return 0;
    }
  • 相关阅读:
    XAML
    诺基亚Lumia 800越狱教程
    Windows Phone常用控件
    Windows Phone数据存储
    Silverlight自定义鼠标
    [silverlight] silverlight3新增功能1:三维效果(透视转换)
    [silverlight] silverlight3新增功能2:WriteableBitmap
    另一种方法实现silverlight图片局部放大效果
    [Silverlight]简单实现DataGrid使用CheckBox选择行
    好用的模糊搜索下拉提示
  • 原文地址:https://www.cnblogs.com/2016gdgzoi471/p/9476869.html
Copyright © 2011-2022 走看看