【BZOJ3456】轩辕朗的城市规划 EGF+多项式求ln

我们构造f(i)g(i)

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

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

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

然后我们构造f(x)g(x)EGF

F(x)=i=0f(i)×xii!

G(x)=i=0g(i)×xii! =i=02(x2)×xii!

然后我们又不难发现,G(x)=i=0F(x)ii!(这个式子可以这样理解:图中包含1个联通块的生成函数为F(x),包含2个连通块的生成函数为12F2(x),包含3个连通块的生成函数为13!F3(x),以此类推)

考虑到ex的泰勒展开式为i=0xii!,则 G(x)=eF(x)

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

则答案为[xn]F(n)×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\n",f[n]*fac[n]%MOD);
91 }
复制代码

 

posted @   AlphaInf  阅读(291)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示