BZOJ3456 城市規劃 分治NTT

2021-08-19 00:24:37 字數 4141 閱讀 4448

這題有複雜度更優秀的做法,比如:miskcoo的多項式求逆與wzq_qwq的多項式求lnln

(os:什麼?還可以求ln?)

當然me都不會上面的,於是式子推到一半就直接硬上了hhhhh。然而狂t不止,優化一波常數卡到了18s

(果然還是優秀做法比較友好)

bzoj3456傳送門

求出n個點帶標號的簡單無向連通圖的個數

答案對 1004535809 取模 n≤

130000

n

≤130000

輸入格式:

僅乙個數字n,含義如題

輸出格式:

輸出乙個數字,表示答案

使用慣用式 圖的計數類dp(以下均預設帶標號) 假設f

[i] f[i

]表示

i i

個點的連通圖的個數,g[

i]' role="presentation">g[i

]g[i

]表示連通圖的個數

顯然有g[i

]=2c

2ig [i

]=2c

i2

,即每條邊都可以選或不選

然後我們來統計f[

i]f [i

],為了不重複計數,需要一點小技巧。我們每次列舉和「編號最小的那個點」連通的點是哪一些,這樣總不會算重複f[

i]=g

[i]−

∑ij=

1f[j

]∗cj

−1i−

1∗g[

i−j]

f [i

]=g[

i]−∑

j=1i

f[j]

∗ci−

1j−1

∗g[i

−j

](列舉上界為i−

1 i−1

也可以,因為當

j j

取i時值為0)

補集轉化,考慮一定不連通的圖。除開「編號最小點」,從i−

1' role="presentation">i−1

i−1個點中選出j−

1 j−1

個點和「編號最小點」在同一連通塊的方案數,記這一部分為

s s

,則|s

|=f[

j]∗c

i−1j

−1' role="presentation">|s|

=f[j

]∗cj

−1i−

1|s|

=f[j

]∗ci

−1j−

1。剩下的部分,在內部隨意連邊,記這一部分為

g g

,則|g

|=g[

i−j]

' role="presentation">|g|

=g[i

−j]|

g|=g

[i−j

]。 因為g

g

和s' role="presentation">s

s之間沒有邊,所以統計不會重複;因為列舉了

s s

的大小,所以統計不會有遺漏

然後答案就是f[

n]' role="presentation">f[n

]f[n

],我們進一步化簡上面的式子,得到f[

i]=g

[i]−

(i−1

)!∑i

−1j=

1f[j

](j−

1)!2

c2i−

j(i−

j)! f[i

]=g[

i]−(

i−1)

!∑j=

1i−1

f[j]

(j−1

)!2c

i−j2

(i−j

)!

發現它是乙個,自己和自己卷積的形式,於是我們使用分治ntt來完成計算

優化常數小技巧

利用迴圈卷積。記當前處理的區間長度為

l l

,我們實際上只需要卷積的

0.5l

' role="presentation">0.5

l0.5l到

l l

的部分,而其它的部分都是廢的…所以我們沒有必要把ntt的開到兩倍區間長度,而只用開到一倍(

f' role="presentation">f

f的部分是

0.5l

0.5l

,而gg

的部分是

l' role="presentation">l

l,所以卷積次數最高是

1.5l

1.5l

。我們把區間開到剛好大於

l l

,那麼多出去的部分只會和

0' role="presentation">00到

0.5l

0.5l

發生混疊,不會影響到我們需要的部分)

優化取模,在ntt裡面主要是加減法運算,而僅僅是加減法是無法超過long long的。所以我們只在有乘法的部分取模。在最後把所有數字都取模即可

小範圍暴力,當區間長度很小的時候,沒有必要再呼叫ntt,因為有常數,所以暴力跑得比ntt還快……

**裡其實還有很多可以優化的地方

不過懶得搞了…

#include 

#include

#include

#include

using

namespace

std ;

const

int p = 1004535809 , g = 3 ;

int n ;

long

long fac[130005] , ifac[130005] , mi2c[130005] ;

long

long f[270005] , g[270005] , ans[130005] ;

int s_pow( long

long x , int b ) return rt ;

}void getg()

} if( t != 1 ) yx[++ycnt] = t ;

for( int i = 2 ; i ; i ++ )

if( ok ) return ( void ) printf( "g = %d" , i ) ;

}}void prework()

void ntt( long

long *a , int len , int rev )

for( int i = 2 ; i <= len ; i <<= 1 )

}}for( int i = 0 , t = ( rev == -1 ? s_pow( len , p - 2 ) : 1 ) ; i < len ; i ++ )

a[i] = a[i] %p * t %p ;

}void div_and_conquer( int lf , int rg ) return ;

} int mid = ( lf + rg ) >> 1 , len , t = rg - lf + 1 ;

div_and_conquer( lf , mid ) ;

for( len = 1 ; len <= t ; len <<= 1 ) ;

memset( f , 0 , sizeof( long

long ) * len ) ;

memset( g , 0 , sizeof( long

long ) * len ) ;

for( int i = 1 , j = lf ; i < t ; i ++ , j ++ ) ntt( f , len , 1 ) , ntt( g , len , 1 ) ;

for( int i = 0 ; i < len ; i ++ )

f[i] = f[i] * g[i] %p ;

ntt( f , len , -1 ) ;

for( int i = mid + 1 ; i <= rg ; i ++ )

ans[i] = ( ans[i] - fac[i-1] * f[i-lf+1]%p )%p ;

div_and_conquer( mid+1 , rg ) ;

}void solve()

int main()

bzoj 3456 城市規劃

題意 求n個點的無向連通圖個數 n個點不同,答案對1004535809取模 n 130000 題解 生成函式的種種神奇應用 不過這玩意真是越來越不oi了 笑 這道題首先考慮遞推公式 設f x 為結點數為x的答案 那麼用總的無向圖數減去不連通的無向圖數目就是答案 f i 2 i i 1 2 f j 2...

bzoj3456 城市規劃

time limit 40 sec memory limit 256 mb submit 342 solved 204 submit status discuss 剛剛解決完電力網路的問題,阿狸又被領導的任務給難住了.剛才說過,阿狸的國家有n個城市,現在國家需要在某些城市對之間建立一些 路線,使得整...

bzoj 3456 城市規劃

好像歐爺很久以前就考過這道題了,然而我這個幼兒園小同學到現在才寫 懶得寫題解了,寫完後找幾份好點的題解搬了 求 n 個點無標號簡單無向連通圖個數。方法1那個所謂的 麥克勞林級數 說得有點高階。其實那個式子就是指數生成函式,然後根據某些特性 當然我不會證 指數生成函式可以表示成 e 的冪。方法2 最後...