zoukankan      html  css  js  c++  java
  • 【BZOJ3456】轩辕朗的城市规划 EGF+多项式求ln

    我们构造$f(i)$和$g(i)$。

    其中$f(x)$表示由$x$个节点构成的无向简单连通图的个数。

    $g(x)$表示有$x$个节点构成的无向简单图(不要求连通)的个数。

    显然,由$x$个节点构成的无向简单图最多能有$inom{x}{2}$条边,那么$g(x)=2^{inom{x}{2}}$。

    然后我们构造$f(x)$和$g(x)$的$EGF$:

    $F(x)=sum_{i=0}^{infty} f(i) imes frac{x^i}{i!}$。

    $G(x)=sum_{i=0}^{infty} g(i) imes frac{x^i}{i!} =sum_{i=0}^{infty} 2^{inom{x}{2}} imes frac{x^i}{i!}$。

    然后我们又不难发现,$G(x)=sum_{i=0}^{infty} frac{F(x)^i}{i!}$。(这个式子可以这样理解:图中包含$1$个联通块的生成函数为$F(x)$,包含$2$个连通块的生成函数为$frac{1}{2}F^2(x)$,包含$3$个连通块的生成函数为$frac{1}{3!} F^3(x)$,以此类推)

    考虑到$e^x$的泰勒展开式为$sum_{i=0}^{infty} frac{x^i}{i!}$,则 $G(x)=e^{F(x)}$。

    由于多项式$G(x)$我们已经求得,则$F(x)=ln(G(x))$。

    则答案为$[x^n]F(n) imes n!$。

    考虑到多项式求ln的时间复杂度为O(n long n),则该算法的时间复杂度为O(n log n)。

     

     1 #include<bits/stdc++.h>
     2 #define M (1<<19)
     3 #define L long long
     4 #define G 3
     5 #define MOD 1004535809
     6 using namespace std;
     7 
     8 L pow_mod(L x,L k){
     9     L ans=1;
    10     while(k){
    11         if(k&1) ans=ans*x%MOD;
    12         x=x*x%MOD; k>>=1;
    13     }
    14     return ans;
    15 }
    16 
    17 void change(L a[],int n){
    18     for(int i=0,j=0;i<n-1;i++){
    19         if(i<j) swap(a[i],a[j]);
    20         int k=n>>1;
    21         while(j>=k) j-=k,k>>=1;
    22         j+=k;
    23     }
    24 }
    25 void NTT(L a[],int n,int on){
    26     change(a,n);
    27     for(int h=2;h<=n;h<<=1){
    28         L wn=pow_mod(G,(MOD-1)/h);
    29         for(int j=0;j<n;j+=h){
    30             L w=1;
    31             for(int k=j;k<j+(h>>1);k++){
    32                 L u=a[k],t=a[k+(h>>1)]*w%MOD;
    33                 a[k]=(u+t)%MOD;
    34                 a[k+(h>>1)]=(u-t+MOD)%MOD;
    35                 w=w*wn%MOD;
    36             }
    37         }
    38     }
    39     if(on==-1){
    40         L inv=pow_mod(n,MOD-2);
    41         for(int i=0;i<n;i++) a[i]=a[i]*inv%MOD;
    42         reverse(a+1,a+n);
    43     }
    44 }
    45 
    46 void getinv(L a[],L b[],int n){
    47     if(n==1){b[0]=pow_mod(a[0],MOD-2); return;}
    48     static L c[M],d[M];
    49     memset(c,0,M<<3); memset(d,0,M<<3);
    50     getinv(a,c,n>>1);
    51     for(int i=0;i<n;i++) d[i]=a[i];
    52     NTT(d,n<<1,1); NTT(c,n<<1,1);
    53     for(int i=0;i<(n<<1);i++) b[i]=(2*c[i]-d[i]*c[i]%MOD*c[i]%MOD+MOD)%MOD;
    54     NTT(b,n<<1,-1);
    55     for(int i=0;i<n;i++) b[i+n]=0;
    56 }
    57 
    58 void qiudao(L a[],L b[],int n){
    59     for(int i=1;i<n;i++) b[i-1]=a[i]*i%MOD;
    60 }
    61 void jifen(L a[],L b[],int n){
    62     for(int i=0;i<n;i++) b[i+1]=a[i]*pow_mod(i+1,MOD-2)%MOD;
    63 }
    64 
    65 void getln(L a[],L b[],int n){
    66     static L inva[M],pia[M];
    67     memset(inva,0,M<<3); memset(pia,0,M<<3);
    68     getinv(a,pia,n); qiudao(a,inva,n); 
    69     NTT(pia,n<<1,1); NTT(inva,n<<1,1);
    70     for(int i=0;i<(n<<1);i++) pia[i]=pia[i]*inva[i]%MOD;
    71     NTT(pia,n<<1,-1);
    72     jifen(pia,b,n);
    73 }
    74 
    75 L a[M]={0},f[M]={0};
    76 L fac[M]={0},invfac[M]={0};
    77 
    78 int main(){
    79     fac[0]=1;
    80     int n; scanf("%d",&n);
    81     int nn=1; while(nn<=n) nn<<=1;
    82 
    83     for(int i=1;i<nn;i++) fac[i]=fac[i-1]*i%MOD;
    84     invfac[nn-1]=pow_mod(fac[nn-1],MOD-2);
    85     for(int i=nn-2;~i;i--) invfac[i]=invfac[i+1]*(i+1)%MOD;
    86 
    87     for(L i=0;i<nn;i++) a[i]=pow_mod(2,i*(i-1)/2)*invfac[i]%MOD;
    88     getln(a,f,nn);
    89     
    90     printf("%lld
    ",f[n]*fac[n]%MOD);
    91 }
  • 相关阅读:
    浏览器和node中的event loop的区别
    path.resolve(dir)与path.join(__dirname,dir)的区别
    如何在typescript项目中使用eslint
    eslint无法检测ts类型错误
    todo
    brew update 卡住
    async await原理
    node的require
    Hive表头导出成csv文件
    算法--决策树
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/9071769.html
Copyright © 2011-2022 走看看