多项式全家桶

一.多项式牛顿迭代法

已知多项式 \(G(x)\) ,求 \(F(x)\) ,满足:

\[G(F(x)) \equiv 0 \pmod {x^n} \]


假设我们有一个 \(F_0(x)\) 满足:

\[G(F_0(x)) \equiv 0 \pmod{x^{\lceil \frac{n}{2} \rceil}} \]

由定义可知:

\[F(x)-F_0(x)\equiv 0 \pmod{x^{\lceil \frac{n}{2} \rceil}} \]

\[\Rightarrow \forall k \ge 2, \left( F(x)-F_0(x) \frac{}{} \right)^k \equiv 0 \pmod{x^n} \]

由泰勒展开:

\[\sum_{i=0}^{\infty} \frac{G^{(i)}(F_0(x))}{i!}(F(x)-F_0(x))^i \equiv 0 \pmod{x^n} \]

\[\Rightarrow G(F_0(x))+G'(F_0(x))(F(x)-F_0(x)) \equiv 0 \pmod {x^n} \]

\[\Rightarrow F(x) \equiv F_0(x)-\frac{G(F_0(x))}{G'(F_0(x))} \pmod {x^n} \]

二.多项式乘法逆

已知多项式 \(G(x)\) ,求 \(F(x)\) ,满足:

\[F(x)G(x) \equiv 1 \pmod {x^n} \]


假设我们有一个 \(F_0(x)\) 满足:

\[F_0(x)G(x) \equiv 1 \pmod{x^{\lceil \frac{n}{2} \rceil}} \]

由 (一) 可知:

\[\left( F(x)-F_0(x) \frac{}{} \right)^2 \equiv 0 \pmod{x^n} \]

\[\Rightarrow F^2(x)-2F(x)F_0(x)+F_0^2(x) \equiv 0 \pmod{x^n} \]

同乘 \(G(x)\):

\[\Rightarrow F(x)-2F_0(x)+F_0^2(x)G(x) \equiv 0 \pmod{x^n} \]

\[\Rightarrow F(x) \equiv F_0(x)\left( 2-F_0(x)G(x) \frac{}{} \right)\pmod{x^n} \]

注意 \(g\) 的长度也要控制为 \(len\) , 不然就退化成 \(\mathcal{O}(nlog^2n)\) 的了。

Poly Inv( Poly g ) {
	Poly f = Poly( 1 , Inv( g[ 0 ] ) ) , A;
	for( int len = 2 ; len < 2 * len( g ) ; len <<= 1 ) {
        A = g; A.resize( len ); //!!!
        Poly tmp = f * A; tmp.resize( len );
		f = f * ( 2 - tmp ); f.resize( len );
	}
	return f;
}

虽然好写但不知道为什么常数那么大

三.多项式导数

\[F(x)=\sum_{i=0}^n f_ix^i \]

\[\begin{aligned} \Rightarrow F'(x)&= \sum_{i=1}^{n} if_i x^{i-1} \\ &= \sum_{i=0}^{n-1} (i+1)f_{i+1} x^i \end{aligned}\]

Poly Der( Poly f ) {
	for( int i = 0 ; i < len( f ) - 1 ; i ++ ) f[ i ] = Mul( i + 1 , f[ i + 1 ] );
	f[ len( f ) - 1 ] = 0;
	return f;
}

四.多项式积分

\[F(x)=\sum_{i=0}^n f_ix^i \]

\[\begin{aligned} \Rightarrow \int F(x)&= \sum_{i=0}^{n} \frac{f_i}{i+1} x^{i+1}\\ &= \sum_{i=1}^{n+1} \frac{f_{i-1}}{i} x^{i}\\ \end{aligned}\]

Poly Int( Poly f ) {
	f.resize( len( f ) + 1 );
	for( int i = len( f ) - 1 ; i >= 1 ; i -- ) f[ i ] = Mul( f[ i - 1 ] , iv[ i ] );
	f[ 0 ] = 0;
	return f;
}

五.多项式 ln

已知多项式 \(G(x)\) , 求 \(F(x)\) , 满足:

\[F(x) \equiv \ln G(x) \pmod{x^n} \]


两边同时求导 (注意右式为复合函数):

\[F'(x) \equiv \frac{G'(x)}{G(x)} \pmod{x^n} \]

算完后积分回来就好了。

因为保证 \(g(0)=1\) , 所以积分常数 \(C\)\(0\)

Poly Ln( Poly f ) {
	return Int( Der( f ) * Inv( f ) );
}

六.多项式 exp

已知多项式 \(G(x)\) , 求 \(F(x)\) , 满足:

\[F(x) \equiv e^{G(x)} \pmod{x^n} \]


两边取 ln:

\[\ln F(x) \equiv G(x) \pmod{x^n} \]

\[\ln F(x)-G(x) \equiv 0 \pmod{x^n} \]

\(H(F(x)) \equiv \ln F(x) - G(x) \equiv 0 \pmod{x^n}\)

两边求导:

\[H'(F(x)) \equiv \frac{1}{F(x)} \pmod{x^n} \]

\[\]

用牛顿迭代展开:

\[F(x) \equiv F_0(x)-\frac{H (F_0(x))}{H'(F_0(x))} \pmod {x^n}\]

\[\Rightarrow F(x) \equiv F_0(x)-\frac{\ln F_0(x)-G(x)}{F_0^{-1}(x)} \pmod {x^n} \]

\[\Rightarrow F(x) \equiv F_0(x)\left( 1-\ln F_0(x)+G(x) \frac{}{} \right) \pmod {x^n} \]

Poly Exp( Poly f ) {
	Poly g = Poly( 1 , 1 );
	for( mxlen = 2 ; mxlen < 4 * len( f ) ; mxlen <<= 1 ) {
		Poly A = f; A.resize( mxlen );
		g = g * ( ( 1 - Ln( g ) ) + A );
	}
	g.resize( len( f ) ); return g;
}

不知道为什么 mxlen 需要到 \(4\) 倍,希望有好心人指出。

七.多项式幂函数

已知多项式 \(G(x)\) , 求 \(F(x)\) , 满足:

\[F(x) \equiv G^k(x) \pmod{x^n} \]


同时取 ln 得到:

\[\ln F(x) \equiv k \ln G(x) \pmod{x^n} \]

然后 exp 回去即可。

常数一目了然,不言而喻

Poly pow( Poly f , int k ) {
	f = Ln( f ); f = f * k; f = Exp( f );
	return f;
}

八.多项式开根

已知多项式 \(G(x)\) , 求 \(F(x)\) , 满足:

\[F(x) \equiv \sqrt{G(x)} \pmod{x^n} \]


法一

使用多项式幂函数计算 \(G^{\frac{1}{2}}(x)\) ,复杂度 \(\mathcal{O(n \log n)}\)

吸氧才能过

法二

\[F(x) \equiv \sqrt{G(x)} \pmod{x^n} \]

\[\Rightarrow F^2(x) - G(x) \equiv 0 \pmod{x^n} \]

\(H(F(x)) \equiv F^2(x)-G(x) \equiv 0\)

两边求导:

\[H'(F(x))=2F(x) \]

用牛顿迭代展开:

\[F(x) \equiv F_0(x)-\frac{H (F_0(x))}{H'(F_0(x))} \pmod {x^n}\]

\[\Rightarrow F(x) \equiv F_0(x)-\frac{F_0^2(x)-G(x)}{2F_0(x)} \pmod {x^n} \]

\[\Rightarrow F(x) \equiv \frac{F_0^2(x)+G(x)}{2F_0(x)} \pmod {x^n} \]

复杂度同样是 \(\mathcal{O(n \log n)}\)


当常数项不为 \(1\) 时,可以用二次剩余算出结果。

九.多项式除法

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 Quick_pow( 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 Quick_pow( x , Mod - 2 ); }
int iv[ MAXN + 5 ];
void Init() {
	iv[ 1 ] = 1;
	for( int i = 2 ; i <= MAXN ; i ++ ) iv[ i ] = Mul( Mod - Mod / i , iv[ Mod % 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 = 332748118;
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 = Quick_pow( 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;
}
Poly Der( Poly f ) {
	for( int i = 0 ; i < len( f ) - 1 ; i ++ ) f[ i ] = Mul( i + 1 , f[ i + 1 ] );
	f.resize( len( f ) - 1 );
	return f;
}
Poly Int( Poly f ) {
	f.resize( len( f ) + 1 );
	for( int i = len( f ) - 1 ; i >= 1 ; i -- ) f[ i ] = Mul( f[ i - 1 ] , iv[ i ] );
	f[ 0 ] = 0;
	return f;
}
Poly Ln( Poly f ) {
	Poly g = Int( Der( f ) * Inv( f ) );
	g.resize( len( f ) ); return g;
}
Poly Exp( Poly f ) {
	Poly g = Poly( 1 , 1 );
	for( mxlen = 2 ; mxlen < 4 * len( f ) ; mxlen <<= 1 ) {
		Poly A = f; A.resize( mxlen );
		g = g * ( ( 1 - Ln( g ) ) + A );
	}
	g.resize( len( f ) ); return g;
}
Poly Pow( Poly f , int k ) {
	f = Ln( f ); f = f * k; f = Exp( f );
	return f;
}
Poly Sqrt( Poly f ) {
	Poly g = Poly( 1 , 1 );
	for( mxlen = 2 ; mxlen < 4 * len( f ) ; mxlen <<= 1 ) {
		Poly A = f; A.resize( mxlen );
		g = ( g + ( A * Inv( g ) ) ) * Inv( 2 );
	}
	g.resize( len( f ) ); return g;
}
posted @ 2021-03-16 20:24  chihik  阅读(322)  评论(0编辑  收藏  举报