[BZOJ3456]城市规划(生成函数+多项式求逆+多项式求ln)

城市规划

时间限制:40s      空间限制:256MB

题目描述

 刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了.
 刚才说过, 阿狸的国家有n个城市, 现在国家需要在某些城市对之间建立一些贸易路线, 使得整个国家的任意两个城市都直接或间接的连通. 为了省钱, 每两个城市之间最多只能有一条直接的贸易路径. 对于两个建立路线的方案, 如果存在一个城市对, 在两个方案中是否建立路线不一样, 那么这两个方案就是不同的, 否则就是相同的. 现在你需要求出一共有多少不同的方案.
 好了, 这就是困扰阿狸的问题. 换句话说, 你需要求出n个点的简单(无重边无自环)无向连通图数目.
 由于这个数字可能非常大, 你只需要输出方案数mod 1004535809(479 * 2 ^ 21 + 1)即可.


输入格式

 仅一行一个整数n(<=130000)
 


输出格式

 仅一行一个整数, 为方案数 mod 1004535809.
 


样例输入

 3


样例输出

 4

提示

 对于 100%的数据, n <= 130000


题目来源

没有写明来源

传说中FFT应用的最高境界?现在恐怕配不上这个称号了。

http://blog.miskcoo.com/2015/05/bzoj-3456

解法一:

先按照惯例减弱条件限制,不要求图连通,再将连通和不联通之间的递推关系式化成卷积的形式。最后直接上生成函数,在模$x^{n+1}$下求多项式的逆元即可。

次数界放宽!递归求逆元的时候次数界要放成两倍!

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define rep(i,l,r) for (int i=l; i<=r; i++)
 4 using namespace std;
 5 
 6 const int N=300100,mod=1004535809,g=3;
 7 int n,m,a[N],b[N],lg[N<<1],fac[N],fin[N],tmp[N],c[N],b1[N],rev[N];
 8 
 9 int ksm(int a,int b){
10     int res;
11     for (res=1; b; a=1ll*a*a%mod,b>>=1)
12         if (b&1) res=1ll*res*a%mod;
13     return res;
14 }
15 
16 void DFT(int a[],int n,int f){
17     for (int i=0; i<n; i++) if (i<rev[i]) swap(a[i],a[rev[i]]);
18     for (int i=1; i<n; i<<=1){
19         int wn=ksm(g,(f==1) ? (mod-1)/(i<<1) : (mod-1)-(mod-1)/(i<<1));
20         for (int p=i<<1,j=0; j<n; j+=p){
21             int w=1;
22             for (int k=0; k<i; k++,w=1ll*w*wn%mod){
23                 int x=a[j+k],y=1ll*w*a[i+j+k]%mod; a[j+k]=(x+y)%mod; a[i+j+k]=(x-y+mod)%mod;
24             }
25         }
26     }
27     if (f==1) return;
28     int inv=ksm(n,mod-2);
29     for (int i=0; i<n; i++) a[i]=1ll*a[i]*inv%mod;
30 }
31 
32 void get(int a[],int b[],int l){
33     if (l==1){ b[0]=ksm(a[0],mod-2); return ;}
34     get(a,b,l>>1); int n=l<<1;
35     for (int i=0; i<l; i++) tmp[i]=a[i],tmp[i+l]=0;
36     
37     for (int i=0; i<n; i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg[n]-1));
38     DFT(tmp,n,1); DFT(b,n,1);
39     for (int i=0; i<n; i++) tmp[i]=1ll*b[i]*(2-1ll*tmp[i]*b[i]%mod+mod)%mod;
40     DFT(tmp,n,-1);
41     
42     for (int i=0; i<l; i++) b[i]=tmp[i],b[i+l]=0;
43 }
44 
45 int main(){
46     freopen("bzoj3456.in","r",stdin);
47     freopen("bzoj3456.out","w",stdout);
48     scanf("%d",&n); fac[0]=fin[0]=1; lg[1]=0;
49     rep(i,2,n<<2) lg[i]=lg[i>>1]+1;
50     rep(i,1,n) fac[i]=1ll*fac[i-1]*i%mod;
51     fin[n]=ksm(fac[n],mod-2);
52     for (int i=n-1; i; i--) fin[i]=1ll*fin[i+1]*(i+1)%mod;
53     rep(i,0,n) b[i]=1ll*ksm(2,1ll*i*(i-1)/2%(mod-1))*fin[i]%mod;
54     rep(i,1,n) c[i]=1ll*ksm(2,1ll*i*(i-1)/2%(mod-1))*fin[i-1]%mod;
55     for (m=1; m<=n; m<<=1); get(b,b1,m);
56     DFT(c,m<<1,1); DFT(b1,m<<1,1);
57     for (int i=0; i<(m<<1); i++) c[i]=1ll*c[i]*b1[i]%mod;
58     DFT(c,m<<1,-1); printf("%lld\n",1ll*c[n]*fac[n-1]%mod);
59     return 0;
60 }

 解法二:指数型生成函数

惊奇地发现正好要求的函数可以放在exp的指数上,多项式求ln即可。

形式幂级数什么的真是太有意思了。

https://blog.csdn.net/u014609452/article/details/56291323

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define rep(i,l,r) for (int i=l; i<=r; i++)
 4 using namespace std;
 5 
 6 const int N=600100,mod=1004535809,g=3;
 7 int n,m,G[N],G1[N],invG[N],lg[N<<1],fac[N],fin[N],tmp[N],c[N],b1[N],rev[N];
 8 
 9 int ksm(int a,int b){
10     int res;
11     for (res=1; b; a=1ll*a*a%mod,b>>=1)
12         if (b&1) res=1ll*res*a%mod;
13     return res;
14 }
15 
16 void DFT(int a[],int n,int f){
17     for (int i=0; i<n; i++) if (i<rev[i]) swap(a[i],a[rev[i]]);
18     for (int i=1; i<n; i<<=1){
19         int wn=ksm(g,(f==1) ? (mod-1)/(i<<1) : (mod-1)-(mod-1)/(i<<1));
20         for (int p=i<<1,j=0; j<n; j+=p){
21             int w=1;
22             for (int k=0; k<i; k++,w=1ll*w*wn%mod){
23                 int x=a[j+k],y=1ll*w*a[i+j+k]%mod; a[j+k]=(x+y)%mod; a[i+j+k]=(x-y+mod)%mod;
24             }
25         }
26     }
27     if (f==1) return;
28     int inv=ksm(n,mod-2);
29     for (int i=0; i<n; i++) a[i]=1ll*a[i]*inv%mod;
30 }
31 
32 void get(int a[],int b[],int l){
33     if (l==1){ b[0]=ksm(a[0],mod-2); return ;}
34     get(a,b,l>>1); int n=l<<1;
35     for (int i=0; i<l; i++) tmp[i]=a[i],tmp[i+l]=0;
36     
37     for (int i=0; i<n; i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg[n]-1));
38     DFT(tmp,n,1); DFT(b,n,1);
39     for (int i=0; i<n; i++) tmp[i]=1ll*b[i]*(2-1ll*tmp[i]*b[i]%mod+mod)%mod;
40     DFT(tmp,n,-1);
41     
42     for (int i=0; i<l; i++) b[i]=tmp[i],b[i+l]=0;
43 }
44 
45 int main(){
46     freopen("bzoj3456.in","r",stdin);
47     freopen("bzoj3456.out","w",stdout);
48     scanf("%d",&n); fac[0]=fin[0]=1; lg[1]=0;
49     rep(i,2,n<<3) lg[i]=lg[i>>1]+1;
50     rep(i,1,n) fac[i]=1ll*fac[i-1]*i%mod;
51     fin[n]=ksm(fac[n],mod-2);
52     for (int i=n-1; i; i--) fin[i]=1ll*fin[i+1]*(i+1)%mod;
53     
54     G[0]=G[1]=1; G1[n]=0;
55     rep(i,0,n) G[i]=1ll*ksm(2,(1ll*i*(i-1)/2)%(mod-1))*fin[i]%mod;
56     rep(i,1,n) G1[i-1]=1ll*G[i]*i%mod;
57     
58     for (m=1; m<=n; m<<=1); get(G,invG,m); m<<=1;
59     DFT(G1,m,1); DFT(invG,m,1);
60     for (int i=0; i<m; i++) G1[i]=1ll*invG[i]*G1[i]%mod;
61     DFT(G1,m,-1);
62     
63     printf("%lld\n",(1ll*G1[n-1]*ksm(n,mod-2)%mod)*fac[n]%mod);
64     return 0;
65 }

 

posted @ 2018-04-01 18:05  HocRiser  阅读(463)  评论(0编辑  收藏  举报