BZOJ3456 城市规划 【生成函数】【FFT】

题目分析:

容易想到生成函数的构造方法。

令g(n)表示n个点的无向图个数,f(n)表示n个点的无向连通图的个数。式子是显然的。

容易发现式子是卷积的形式,写出生成函数,然后多项式求逆后多项式乘法即可。

代码:

  

#include<bits/stdc++.h>
using namespace std;

int n;

const int maxn = 800000;
const int mod = 1004535809;
const int gg = 3;

int A[maxn],B[maxn],IB[maxn],B0[maxn],F[maxn];
int fac[maxn/4],ord[maxn];

int fast_pow(int now,long long pw){
    if(pw == 0) return 1;
    if(pw == 1) return now;
    int z = fast_pow(now,pw/2);
    z = (1ll*z*z)%mod;
    if(pw & 1) z = (1ll*z*now)%mod;
    return z;
}

void FFT(int *d,int len,int dr){
    for(int i=0;i<len;i++) if(ord[i] < i) swap(d[i],d[ord[i]]);
    for(int i=1;i<len;i<<=1){
    int wn = fast_pow(gg,(mod-1)/(i<<1));
    if(dr == -1) wn = fast_pow(wn,mod-2);
    for(int j=0;j<len;j+=(i<<1)){
        int w = 1;
        for(int k=0;k<i;k++,w=(1ll*w*wn)%mod){
        int x = d[j+k],y = (1ll*w*d[j+k+i])%mod;
        d[j+k] = (x+y)%mod; d[j+k+i] = (x-y)%mod;
        if(d[j+k+i] < 0) d[j+k+i]+=mod;
        }
    }
    }
    if(dr == -1){
    int iv = fast_pow(len,mod-2);
    for(int i=0;i<len;i++) d[i] = (1ll*d[i]*iv)%mod;
    }
}

void GetA(){
    for(int i=0;i<=n;i++)
    A[i] = (1ll*fast_pow(2,1ll*i*(i-1)/2)*fast_pow(fac[i-1],mod-2))%mod;
}

void GetB(){
    for(int i=0;i<=n;i++)
    B[i] = (1ll*fast_pow(2,1ll*i*(i-1)/2)*fast_pow(fac[i],mod-2))%mod;
}

void Inv(){
    IB[0] = fast_pow(B[0],mod-2);
    int res = 1;
    while(res < n+1) res=res<<1;
    for(int i=2,j=1;i<=res;i<<=1,j++){
    int bit = i*2,om = j+1;
    for(int k=0;k<i;k++) B0[k] = B[k];
    for(int k=0;k<bit;k++) ord[k]=(ord[k>>1]>>1)+((k&1)<<om-1);
    FFT(IB,bit,1);FFT(B0,bit,1);
    for(int k=0;k<bit;k++) B0[k]=(1ll*B0[k]*((1ll*IB[k]*IB[k])%mod))%mod;
    for(int k=0;k<bit;k++) IB[k] = (1ll*2*IB[k]-B0[k]+mod)%mod;
    FFT(IB,bit,-1);
    for(int k=i;k<2*i;k++) IB[k] = 0;
    }
    for(int i=n;i<=res;i++) IB[i] = 0;
}

void Multi(){
    int res = 1,len = 0;
    while(res < 2*n+1)res = res<<1,len++;
    for(int i=0;i<res;i++) ord[i]=(ord[i>>1]>>1)+((i&1)<<len-1);
    FFT(IB,res,1);FFT(A,res,1);
    for(int i=0;i<res;i++) F[i] = (1ll*A[i]*IB[i])%mod;
    FFT(F,res,-1);
}

void work(){fac[0] = 1;
    for(int i=1;i<=n;i++) fac[i] = (1ll*fac[i-1]*i)%mod;
    GetA();
    GetB();
    Inv();
    Multi();
    F[n] = (1ll*F[n]*fac[n-1])%mod;
    printf("%d",F[n]); 
}

int main(){
    scanf("%d",&n);
    work();
    return 0;
}
原文地址:https://www.cnblogs.com/Menhera/p/8985887.html