P4841 [集训队作业2013]城市规划

\(g_n\) 表示 \(n\) 个点的无向图数量, \(f_n\) 表示 \(n\) 个点的无向连通图数量。

显然 \(g_n=2^{\binom{n}{2}}\)

同时如果枚举 \(1\) 节点所在的联通块大小可得:

\[\begin{aligned} &g_n=\sum_{i=1}^n \binom{n-1}{i-1}f_ig_{n-i} \\ \Rightarrow &f_n=g_n-\sum_{i=1}^{n-1}\binom{n-1}{i-1}f_ig_{n-i} \\ \end{aligned}\]

这样可以 \(\mathcal{O}(n^2)\) 递推,当然你也可以 \(\mathcal{O}(n\log^2 n)\) 分治 fft 计算。

\[\begin{aligned} g_n&=\sum_{i=1}^n \binom{n-1}{i-1}f_ig_{n-i} \\ \frac{g_n}{(n-1)!}&=\sum_{i=1}^n \frac{f_i}{(i-1)!} \frac{g_{n-i}}{(n-i)!} \end{aligned}\]

\(\displaystyle F(x)=\sum_{i \ge 1} \frac{f_i}{(i-1)!}x^i , G(x)=\sum_{i \ge 0}\frac{g_i}{i!}x^i, G'(x)=\sum_{i \ge 1}\frac{g_i}{(i-1)!}\) ,

\[G' = F * G \Rightarrow F=\frac{G'}{G} \]

多项式求逆即可,时间复杂度 \(\mathcal{O(n \log n)}\)

#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;

const int MAXN = 8e5 , Mod = 1004535809;
int Add( int x , int y ) { x += y; return x >= Mod ? x - Mod : x; }
int Sub( int x , int y ) { x -= y; return x < 0 ? x + Mod : x; }
int Mul( int x , int y ) { return 1ll * x * y % Mod; }
int Qkpow( int x , int po ) { int Ans = 1; for( ; po ; po >>= 1 , x = Mul( x , x ) ) if( po & 1 ) Ans = Mul( Ans , x ); return Ans; }
int Inv( int x ) { return Qkpow( x , Mod - 2 ); }
int iv[ MAXN + 5 ] , fac[ MAXN + 5 ] , ivf[ MAXN + 5 ];
void Init() {
	iv[ 1 ] = 1;
	for( int i = 2 ; i <= MAXN ; i ++ ) iv[ i ] = Mul( Mod - Mod / i , iv[ Mod % i ] );

	fac[ 0 ] = 1;
	for( int i = 1 ; i <= MAXN ; i ++ ) fac[ i ] = Mul( fac[ i - 1 ] , i );
	ivf[ MAXN ] = Inv( fac[ MAXN ] );
	for( int i = MAXN ; i >= 1 ; i -- ) ivf[ i - 1 ] = Mul( ivf[ i ] , i );
}

#define Poly vector< int >
#define len( x ) ( (int)x.size() )
Poly operator - ( int x , Poly f ) { for( int i = 0 ; i < len( f ) ; i ++ ) f[ i ] = Mod - f[ i ]; f[ 0 ] = Add( f[ 0 ] , x ); return f; }
Poly operator - ( Poly f , int x ) { f[ 0 ] = Sub( f[ 0 ] , x ); return f; }
Poly operator * ( Poly f , int x ) { for( int i = 0 ; i < len( f ) ; i ++ ) f[ i ] = Mul( f[ i ] , x ); return f; }
Poly operator + ( Poly f , Poly g ) {
	int n = max( len( f ) , len( g ) ); f.resize( n ); g.resize( n );
	for( int i = 0 ; i < n ; i ++ ) f[ i ] = Add( f[ i ] , g[ i ] );
	return f;
}
Poly operator - ( Poly f , Poly g ) {
	int n = max( len( f ) , len( g ) ); f.resize( n ); g.resize( n );
	for( int i = 0 ; i < n ; i ++ ) f[ i ] = Sub( f[ i ] , g[ i ] );
	return f;
}

const int G = 3 , IG = 334845270;
int lim , ilim , rev[ MAXN + 5 ];
void ntt( Poly &f , int op ) {
	for( int i = 0 ; i < lim ; i ++ ) if( i < rev[ i ] ) swap( f[ i ] , f[ rev[ i ] ] );
	for( int len = 2 , w ; len <= lim ; len <<= 1 ) {
		w = Qkpow( op == 1 ? G : IG , ( Mod - 1 ) / len );
		for( int l = 0 ; l < lim ; l += len ) {
			for( int i = l , wk = 1 ; i < l + len / 2 ; i ++ , wk = Mul( wk , w ) ) {
				int t = Mul( wk , f[ i + len / 2 ] );
				f[ i + len / 2 ] = Sub( f[ i ] , t ); f[ i ] = Add( f[ i ] , t );
			}
		}
	}
	if( op == -1 ) for( int i = 0 ; i < lim ; i ++ ) f[ i ] = Mul( f[ i ] , ilim );
}
int mxlen = 100000000;
Poly operator * ( Poly f , Poly g ) {
	int n = len( f ) + len( g ) - 1; for( lim = 1 ; lim < n ; lim <<= 1 ); ilim = Inv( lim );
	for( int i = 0 ; i < lim ; i ++ ) rev[ i ] = ( rev[ i >> 1 ] >> 1 ) | ( i & 1 ? lim >> 1 : 0 );
	f.resize( lim ); g.resize( lim );
	ntt( f , 1 ); ntt( g , 1 );
	for( int i = 0 ; i < lim ; i ++ ) f[ i ] = Mul( f[ i ] , g[ i ] );
	ntt( f , -1 ); f.resize( min( n , mxlen ) ); 
	return f;
}
Poly Inv( Poly f ) {
	Poly g = Poly( 1 , Inv( f[ 0 ] ) );
	for( mxlen = 2 ; mxlen < 2 * len( f ) ; mxlen <<= 1 ) {
		Poly A = f; A.resize( mxlen );
		g = g * ( 2 - ( g * A ) ); 
	}
	g.resize( len( f ) ); return g;
}

int n;
Poly f , g1 , g2;

int C2( int n ) { return 1ll * n * ( n - 1 ) / 2 % ( Mod - 1 ); }
int main( ) {
	Init();
	scanf("%d",&n); g1.resize( n + 1 ); g2.resize( n + 1 );

	for( int i = 0 ; i <= n ; i ++ ) {
		g1[ i ] = Mul( Qkpow( 2 , C2( i ) ) , ivf[ i ] );
		if( i ) g2[ i ] = Mul( Qkpow( 2 , C2( i ) ) , ivf[ i - 1 ] );
	}
	f = g2 * Inv( g1 );
	printf("%d\n", Mul( f[ n ] , fac[ n - 1 ] ) );
	return 0;
}
posted @ 2021-04-01 15:59  chihik  阅读(57)  评论(0编辑  收藏  举报