這題有複雜度更優秀的做法,比如: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 最後...