1. 程式人生 > >[BZOJ3456]城市規劃(生成函數+多項式求逆+多項式求ln)

[BZOJ3456]城市規劃(生成函數+多項式求逆+多項式求ln)

n) 100% 存在 d+ ont inner tar 現在 一行

城市規劃

時間限制: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 }

[BZOJ3456]城市規劃(生成函數+多項式求逆+多項式求ln)