[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 }