BZOJ3456:城市规划——题解

https://www.lydsy.com/JudgeOnline/problem.php?id=3456

求出n个点的简单(无重边无自环)无向连通图数目

模数很熟悉,先敲一个NTT。

然后通过推导式子就做完啦!

我觉得就算怎么讲也没有下面这一位好:http://blog.miskcoo.com/2015/05/bzoj-3456

另外多项式求逆:http://blog.miskcoo.com/2015/05/polynomial-inverse

至少我学到了:当你有个卷积知道答案,求卷积的一项时转换成生成函数再FFT一下就好了。

#include<cstdio>
#include<cctype>
#include<cstring>
#include<vector>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;
const ll P=1004535809;
const int G=3;
const int N=5e5+5;
ll qpow(ll a,ll n,ll p){
    ll res=1;
    while(n){
        if(n&1)res=res*a%p;
        a=a*a%p;n>>=1;
    }
    return res;
}
void MTT(ll a[],int n,int on){
    for(int i=1,j=n>>1;i<n-1;i++){
        if(i<j)swap(a[i],a[j]);
        int k=n>>1;
        while(j>=k){j-=k;k>>=1;}
        if(j<k)j+=k;
    }
    for(int i=2;i<=n;i<<=1){
        ll res=qpow(G,(P-1)/i,P);
        for(int j=0;j<n;j+=i){
            ll w=1;
            for(int k=j;k<j+i/2;k++){
                ll u=a[k],t=w*a[k+i/2]%P;
                a[k]=(u+t)%P;
                a[k+i/2]=(u-t+P)%P;
                w=w*res%P;
            }
        }
    }
    if(on==-1){
        ll inv=qpow(n,P-2,P);
        a[0]=a[0]*inv%P;
        for(int i=1;i<=n/2;i++){
            a[i]=a[i]*inv%P;
            if(i!=n-i)a[n-i]=a[n-i]*inv%P;
            swap(a[i],a[n-i]);
        }
    }
}
ll t[N];
void inv(int deg,ll a[],ll b[]){
    if(deg==1){
        b[0]=qpow(a[0],P-2,P);
        return;
    }
    inv((deg+1)>>1,a,b);
    int n=1;
    while(n<(deg<<1))n<<=1;
    for(int i=0;i<deg;i++)t[i]=a[i];
    for(int i=deg;i<n;i++)t[i]=0;
    MTT(t,n,1);MTT(b,n,1);
    for(int i=0;i<n;i++)
        b[i]=b[i]*(2-b[i]*t[i]%P+P)%P;
    MTT(b,n,-1);
    for(int i=deg;i<n;i++)b[i]=0;
}
int n;
ll f[N],g[N],tmp[N],c[N],jc[N],C[N][3];
inline void init(){
    jc[0]=jc[1]=1;C[0][2];
    for(int i=2;i<=n;i++)jc[i]=jc[i-1]*i%P;
    for(int i=1;i<=n;i++)C[i][2]=C[i-1][2]+i-1;
}
int main(){
    scanf("%d",&n);init();
    for(int i=0;i<=n;i++){
        g[i]=qpow(2,C[i][2],P)*qpow(jc[i],P-2,P)%P;
        if(i)c[i]=qpow(2,C[i][2],P)*qpow(jc[i-1],P-2,P)%P;
    }
    int nn=1;
    while(nn<=n)nn<<=1;
    
    inv(nn,g,tmp);memcpy(g,tmp,sizeof(tmp));
    
    MTT(g,nn,1);MTT(c,nn,1);
    for(int i=0;i<nn;i++)f[i]=g[i]*c[i]%P;
    MTT(f,nn,-1);
    
    f[n]=f[n]*jc[n-1]%P;
    printf("%lld\n",f[n]);
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/ +

+++++++++++++++++++++++++++++++++++++++++++

posted @ 2018-05-07 21:22  luyouqi233  阅读(318)  评论(0编辑  收藏  举报