[BZOJ3456]城市规划

    科技2022-07-11  118

    Description

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


    Input

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


    Output

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


    Solution


    Code

    #include<bits/stdc++.h> using namespace std; typedef long long ll; const int p=1004535809; int a[300010],b[300010],c[300010],d[300010]; int rev[300010],pg[300010],pinvg[300010],n; int fac[300010]={1},ifac[300010]; int qpow(int x,ll y){ int s=1,bas=x; while(y){ if(y&1) s=(s*1ll*bas)%p; bas=(bas*1ll*bas)%p; y>>=1; } return s; } void NTT(int *A,int limit,int typ){ for(int i=0;i<limit;i++) if(i<rev[i]) swap(A[i],A[rev[i]]); for(int i=1;i<limit;i<<=1){ int wn=typ>0?pg[i<<1]:pinvg[i<<1]; for(int j=0,s=i<<1;j<limit;j+=s) for(int k=0,w=1;k<i;k++,w=(w*1ll*wn)%p){ int x=A[j+k],y=(A[j+k+i]*1ll*w)%p; A[j+k]=(x+y)%p,A[j+k+i]=(x-y+p)%p; } } if(typ<0){ int inv=qpow(limit,p-2); for(int i=0;i<limit;i++) A[i]=(A[i]*1ll*inv)%p; } } void getinv(int *A,int *B,int l){ if(l==1){ B[0]=qpow(A[0],p-2); return; } getinv(A,B,(l+1)>>1); int limit=1,bit=0; while(limit<2*l) limit<<=1,bit++; for(int i=0;i<limit;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1)); for(int i=0;i<l;i++) c[i]=A[i]; for(int i=l;i<limit;i++) c[i]=0; NTT(c,limit,1),NTT(B,limit,1); for(register int i=0;i<limit;i++) B[i]=(2ll-c[i]*1ll*B[i]%p+p)%p*1ll*B[i]%p; NTT(B,limit,-1); for(int i=l;i<limit;i++) B[i]=0; } int invg; void init(int limit){ invg=qpow(3,p-2); for(int i=1;i<=limit;i<<=1) pg[i]=qpow(3,(p-1)/i);//,cout<<p3[i]<<endl; for(int i=1;i<=limit;i<<=1) pinvg[i]=qpow(invg,(p-1)/i); for(int i=1;i<=n;i++) fac[i]=(fac[i-1]*1ll*i)%p; ifac[n]=qpow(fac[n],p-2); for(int i=n;i;i--) ifac[i-1]=(ifac[i]*1ll*i)%p; } int main(){ a[0]=1; scanf("%d",&n); int limit=1,bit=0; while(limit<2*(n+1)) limit<<=1,bit++; init(limit); for(int i=1;i<=n;i++){ int x=qpow(2,i*1ll*(i-1)/2); //cout<<x<<" "<<ifac[i]<<endl; a[i]=(x*1ll*ifac[i])%p; d[i]=(x*1ll*ifac[i-1])%p; } getinv(a,b,n+1); for(int i=0;i<limit;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1)); NTT(b,limit,1),NTT(d,limit,1); for(int i=0;i<limit;i++) b[i]=(b[i]*1ll*d[i])%p; NTT(b,limit,-1); printf("%lld",(b[n]*1ll*fac[n-1])%p); }
    Processed: 0.011, SQL: 8