集訓隊作業 城市規劃

2022-06-04 11:09:07 字數 3195 閱讀 2349

點這裡看題目。

考慮如下遞推:

\(f_i\):\(i\)個點的無向有標號連通圖的個數。

\(g_i\):\(i\)個點的無向有標號圖的個數。

以下給出兩種計算方式。

不難看出乙個式子:

\[g_n=\sum_^n\binomf_ig_

\]這相當於列舉 1 所在的連通塊大小,然後構造出這個連通塊,剩下的點任意連。

然後感覺這個東西非常的 egf ,就嘗試拆一下:

\[\frac=\sum_^n\frac\cdot\frac}

\]由於負數的階乘是未定義的,我們就認為它是 0 ,那麼就可以簡化下標:

\[\frac=\sum_^n\frac\cdot\frac}

\]另外,由於任意乙個無向有標號圖一定是:

\[\begin

&g=(v,e')\\

&v=\\\

&e=\, e'\subseteq e

\end

\]那麼我們可以得到:

\[g_n=2^}

\]實際上就是看每條邊選不選。

帶入到式子中可以得到:

\[\frac}=\sum_^n\frac\cdot \frac 2}}

\]反手寫成生成函式:

\[\begin

h(x)&=\sum_^ \frac}x^i\\

f(x)&=\sum_^ \fracx^i\\

g(x)&=\sum_^ \frac}x^i

\end

\]於是有:

\[\begin

h(x)&=f(x)*g(x)\\

f(x)&=h(x)*g^(x)

\end

\]多項式求逆,結束。時間是\(o(n\log_2n)\)。

為了方便,我們先不考慮標號,記:

\[p_i=\frac,q_i=\frac

\]把它寫成生成函式的形式:

\[\begin

p(x)&=\sum_^ p_ix^i\\

q(x)&=\sum_^ q_ix^i

\end

\]然後可以發現:

\[\begin

q(x)=\sum_^ \frac

\end

\]其中\(k\)是在列舉連通塊的個數;除以\(k!\),是因為\((p(x))^k\)使得連通塊之間存在順序,然而這樣就算重複了,因此要除去。

發現等式右邊是經典的\(e^x\)的展開式,縮回去得到:

\[q(x)=e^

\]轉為\(p(x)=\ln q(x)\)計算即可。時間是\(o(n\log_2n)\)。

兩個方法都是正確的,但是結果看起來還不太一樣,我們進一步分析一下:

可以發現,多項式存在如下的關係:

\[h(x)=xg'(x),f(x)=xp'(x)

\]那麼就有:

\[\begin

f(x)&=\frac\\

x\cdot p'(x)&=x\cdot \frac\\

p'(x)&=\ln' g(x)\\

p(x)&=\ln g(x)

\end

\]所以說兩個方法的結果是統一的。只不過法一的**簡單一些而已

作者太懶了,只有法一的**

#include #include typedef long long ll;

const int mod = 1004535809, phi = mod - 1, g = 3;

const int maxn = 1e6 + 5;

templatevoid read( _t &x )

while( s >= '0' && s <= '9' )

x *= f;

}templatevoid write( _t x )

if( 9 < x )

putchar( x % 10 + '0' );

}int rev[maxn], wp[maxn], wpinv[maxn];

int q[maxn], g[maxn], h[maxn];

int fac[maxn], finv[maxn];

int n;

int qkpow( int base, int indx )

return ret;

}int inv( const int a )

int fix( const int a )

void init( const int len )

void ntt( int *coe, const int len, const int t )

#undef p

if( t > 0 ) return; int inver = inv( len );

for( int i = 0 ; i < len ; i ++ ) coe[i] = 1ll * coe[i] * inver % mod;

}namespace polyinv

int p = n + 1 >> 1, len = 1;

polyinv( p );

while( len < n << 1 ) len <<= 1; init( len );

for( int i = 0 ; i < n ; i ++ ) b[i] = p[i];

for( int i = 0 ; i < len ; i ++ ) f0[i] = f[i], f[i] = 0;

ntt( b, len, 1 ), ntt( f0, len, 1 );

for( int i = 0 ; i < len ; i ++ ) f[i] = 1ll * f0[i] * fix( 2 - 1ll * b[i] * f0[i] % mod ) % mod;

ntt( f, len, -1 );

for( int i = n ; i < len ; i ++ ) f[i] = 0; }

void polyinv( int *ret, int *a, const int n ) }

namespace polymul

}int main()

polyinv :: polyinv( g, g, n );

polymul :: polymul( q, g, n, h, n );

write( 1ll * q[n - 1] * fac[n - 2] % mod ), putchar( '\n' );

return 0;

}

集訓隊互測2013 城市規劃

求n個點的帶標號連通簡單圖的個數。答案對1004535809取模。n 130000 根據套路,首先我們需要求出n個點的帶標號簡單圖的個數,設為g n 顯然我們有g n 2 n n 1 2 考慮設答案為f n 要怎麼求出?列舉1號點所在的聯通塊的大小,我們可以知道 g n i 1n f i ci 1 ...

P4841 集訓隊作業2013 城市規劃

設 f i 表示 i 個點的無向連通圖個數,g i 表示 i 個點的無向圖個數。列舉 1 所在連通塊的大小,有 g i sum limits ic f jg 化簡得 g i sum limits i fracf jg frac sum limits i frac frac 設 f i frac,g ...

P4841 集訓隊作業2013 城市規劃 題解

求 n 個點的有標號的無向連通圖數目。text 1 le n le1.3 times10 5 我們設 g i 表示有 i 個點的有標號無向圖數目,易得 g i 2 考慮列舉每兩個點之間是否連通。設 f i 表示有 i 個點的連通圖數目 即答案所求 則可得 g n sum n c f i g 考慮 1...