多项式

板子

先放一个 \(\rm NTT\) 的板子。

#include<bits/stdc++.h>
#define N 1<<?
#define P ?
using namespace std;
int qpow(int k,int b){
	int ret=1;
	while(b){
		if(b&1)ret=1ll*ret*k%P;
		k=1ll*k*k%P,b>>=1;
	}
	return ret;
}
int f[N],g[N],h[N];
int n,lim=1,r[N];
int gn,tp,inv;
void ntt(int *x,int lim,int opt){
	for(int i=0;i<lim;i++)
		if(r[i]<i)swap(x[i],x[r[i]]);
	for(int m=2,k=1;m<=lim;m<<=1,k<<=1){
		gn=qpow(3,(P-1)/m);
		for(int i=0;i<lim;i+=m){
			for(int j=0,g=1;j<k;j++,g=1ll*g*gn%P){
				tp=1ll*x[i+j+k]*g%P;
				x[i+j+k]=(x[i+j]-tp+P)%P;
				x[i+j]=(x[i+j]+tp)%P;
			}
		}
	}
	if(opt==-1){
		reverse(x+1,x+lim),inv=qpow(lim,P-2);
		for(int i=0;i<lim;i++)
			x[i]=1ll*x[i]*inv%P;
	}
}
int main(){
	//n++;
	while(lim<(n<<1))lim<<=1;
	for(int i=0;i<lim;i++)
		r[i]=(r[i>>1]>>1)+(i&1)*(lim>>1);
	ntt(f,lim,1),ntt(g,lim,1);
	for(int i=0;i<lim;i++)
		h[i]=1ll*f[i]*g[i]%P;
	ntt(h,lim,-1);
	
	return 0;
}

我写的 NTT 里面的 IDFT 会把数组翻转一遍,也有一种是加了一个对单位根求逆的操作。这个东西应该和 FFT 里 IDFT 的那个矩阵差不多,估计只是两种不同的实现。


P4245 【模板】任意模数多项式乘法

用一下三个数作为模数,然后 \(\text{CRT}\) 大力合并:

\[p=998244353=119\times2^{23}+1 \]

\[p=1004535809=479\times2^{21}+1 \]

\[p=469762049=7\times2^{26}+1 \]

这三个质数的原根中都含有 \(3\),就可以写了。

有个问题是合并的时候会爆炸。

\[ans\equiv x\space(\text{mod}\space P_1) \]

\[ans\equiv y\space(\text{mod}\space P_2) \]

\[ans\equiv z\space(\text{mod}\space P_3) \]

先处理前两个:

\[x+k_1P_1=y+k_2P_2 \]

\[k_1\equiv\frac{y-x}{P_1}\space(\text{mod}\space P_2) \]

能够得到 \(ans\equiv x+k_1P_1\space(\text{mod}\space P_1P_2)\),把这个东西记为 \(t\) .

\[t+k_4P_1P_2=z+k_3P_3 \]

\[k_4\equiv\frac{z-t}{P_1P_2}\space(\text{mod}\space P_3) \]

求得 \(ans\equiv t+k_4P_1P_2\space(\text{mod}\space P_1P_2P_3)\) .

细节很烦。做 \(3\)\(\text{NTT}\) 记得清零。

record


P4238 【模板】多项式乘法逆

倍增法,求模 \(x^n\) 的逆元时,假设已求出了模 \(x^{\lceil\frac{n}{2}\rceil}\) 的逆元.

设两者分别为 \(B\)\(B'\)

\[A * B'\equiv1\space(\text{mod}\space x^{\lceil\frac{n}{2}\rceil}),A * B\equiv1\space(\text{mod}\space x^{\lceil\frac{n}{2}\rceil}) \]

\[\Rightarrow B-B'\equiv0\space(\text{mod}\space x^{\lceil\frac{n}{2}\rceil}) \]

平方一下

\[B^2-2BB'+B'^2\equiv0\space(\text{mod}\space x^n) \]

乘一个 \(A\)

\[AB'^2-2B'+B\equiv0\space(\text{mod}\space x^n) \]

\[\Rightarrow B\equiv2B'-AB'^2\space(\text{mod}\space x^n) \]

初始值 \(B_{1}=\{A_0^{-1}\}\) .

往下递归即可。

根据主定理得复杂度为 \(\text{T}(n)=\text{T}(n/2)+n\log n=\text{O}(n\log n)\) .

record


P4512 【模板】多项式除法

\(F_R\)\(F\) 系数翻转后的函数。

那么 \(F_R(x)=F(\frac{1}{x})\cdot x^k\) .

\(f,g,q,r\) 的次数分别为 \(n,m,n-m,m-1\)

\[f(\frac{1}{x})=g(\frac{1}{x})\cdot q(\frac{1}{x})+r(\frac{1}{x}) \]

\[f(\frac{1}{x})\cdot x^n=\Big(g(\frac{1}{x})\cdot x^m\Big)\Big(q(\frac{1}{x})\cdot x^{n-m}\Big)+r(\frac{1}{x})\cdot x^{m-1}\cdot x^{n-m+1} \]

\[f_R(x)=g_R(x) * q_R(x)+r_R(x)\cdot x^{n-m+1} \]

\[q_R(x)\equiv \frac{f_R(x)}{g_R(x)}\space(\text{mod}\space x^{n-m+1}) \]

套一个求逆的板子即可算出 \(q\) .

然后

\[r(x)=f(x)-g(x) * q(x) \]

就做完了。时间复杂度 \(\text{O}(n\log n)\) .

record


P4723 【模板】常系数齐次线性递推

\(\text{Fibonacci}\) 数列是如何展开的?

\(x_5\) 为例:

\(x_5\Rightarrow x_4+x_3\Rightarrow 2x_3+x_2\)

\(\Rightarrow 3x_2+2x_1\Rightarrow 5x_1+3x_0\) .

把下标换成指数,容易发现答案是 \(x^5\) 对其特征多项式 \(x^2-x-1\) 取模的结果。

一般数列的特征多项式是 \(G(x)=x^{k}-f_0x^k-f_1x^{k-1}-\dots-f_{k-1}x^1-f_kx^0\) .

写一个快速幂求 \(F(n)=x^n\)\(G(x)\) 取模的值。

时间复杂度 \(\text{O}(k\log k\log n)\) .

细节调不动了。


P4725 【模板】多项式对数函数(多项式 ln)

\(f(x)=\ln (x)\),则

\[G(x)\equiv f(F(x))\text{ (mod }x^n) \]

利用链式法则,两边求导得

\[G'(x)\equiv f'(F(x))F'(x)\text{ (mod }x^n) \]

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

\(F(x)\) 求逆可得 \(G'(x)\).

积回去:

\[{x^a}'=ax^{a-1},\int x^adx=\frac{1}{a+1}x^{a+1} \]

时间复杂度 \(O(n\log n)\).

record


P4726 【模板】多项式指数函数(多项式 exp)

牛顿迭代

如何得到一个函数 \(f(x)\) 的零点的近似值?

若已经有一个近似值 \(x_0\),用过 \((x_0,f(x_0))\),斜率为 \(f'(x_0)\) 的直线得到与 \(x\) 轴的交点,得到新的 \(x_0\),可以迅速逼近精确值。

切线方程

\[y=f'(x_0)(x-x_0)+f(x_0) \]

\(\displaystyle y=0\rightarrow x=x_0-\frac{f(x_0)}{f'(x_0)}\).

若要求 \(G(x)\) 满足 \(F(G(x))=0\),可以每次令

\[G(x)=G_0(x)-\frac{F(G_0(x))}{F'(G_0(x))} \]

使其逼近真实值。

有一个结论是迭代一次后精度翻倍,不知道怎么证的。

于是每次 \(\displaystyle n\rightarrow \lceil\frac{n}{2}\rceil\) 递归进去做。

\[B(x)\equiv e^{A(x)}\text{ (mod }x^n) \]

\[\ln B(x)-A(x)\equiv 0\text{ (mod }x^n) \]

\(F(x)\rightarrow\ln x\),使 \(\displaystyle F(G(x))=\ln G(x)-A(x)\equiv 0\) 即可。

\[F(G_0(x))'=\frac{G_0'(x)}{G_0(x)} \]

代入上面的式子:

\[\large G(x)=G_0(x)-\frac{\ln G_0(x)-A(x)}{\frac{G_0'(x)}{G0(x)}} \]

\[\large=\frac{G_0(x)(1-\ln G_0(x)+A(x))}{G_0'(x)} \]

每次迭代做一遍多项式求逆、求 \(\ln\) 和乘法。

时间复杂度 \(T(n)=T(\frac{n}{2})+O(n\log n)=O(n\log n)\).

record


P5205 【模板】多项式开根

\(\displaystyle H^2(x)\equiv F(x)\text{ (mod }x^{\lceil\frac{n}{2}\rceil})\).

\[G(x)\equiv H(x)\text{ (mod }x^{\lceil\frac{n}{2}\rceil}) \]

\[(G(x)-H(x))^2\equiv0\text{ (mod }x^n) \]

\[F(x)-2H(x)\cdot G(x)+H^2(x)\equiv0\text{ (mod }x^n) \]

\[G(x)\equiv\frac{F(x)+H^2(x)}{2H(x)}\text{ (mod }x^n) \]

多项式求逆即可。

由主定理得时间复杂度 \(O(n\log n)\).

record


P5245 【模板】多项式快速幂

由于 \(n<p\),所以 \(f(x)^p\equiv a_0=1\),可以将 \(k\) 直接对 \(p\) 取模。

一般地,若 \(f(x)\)\(n\) 次多项式,\(p\) 为质数,有

\[f(x)^p=f(x^p)\text{ (mod }p) \]

归纳法:设 \(f(x)\)\(k\) 阶多项式,且\(f(x)=g(x)+a_kx^k\),结论对 \(k-1\) 次多项式成立。

\[f(x)^p=g(x)^p+a_k^px^{pk}=g(x^p)+a_kx^{pk}=f(x^p) \]

本题使用 \(\ln+\exp\) 即可。时间复杂度 \(O(n\log n)\).

record


P5273 【模板】多项式幂函数(加强版)

不保证 \(f(0)=1\).

\(f(x)\) 的每一项都除以 \(f(0)\)

\[f(x)^k=\Big(\frac{f(x)}{f(0)}\Big)^k\cdot f(0)^k \]

\(f(0)=0\) 怎么办?

考虑将 \(f\) 降次后升次,具体就是找到第一个非 \(0\)\(a_tx^t\)

\[F(x)^k=\Big(\frac{F(x)}{x^t}\Big)^k\cdot x^{tk} \]

然后使用上面的方法即可。时间复杂度 \(O(n\log n)\).

不知道我整出来什么大饼。死活过不去。


P4721 【模板】分治 FFT

\(\rm Sol1\): 容易发现

\[F=1+G\times F \]

\[F=\frac{1}{1-G} \]

多项式求逆即可。

record

\(\rm Sol2\):分治,考虑当前过程中 \(f_x(x\in[l,mid])\)\(f_y(y\in[mid+1,r])\) 的影响。

显然这个值是 \(f_x\cdot g_{y-x}\).

\[f_y=\operatorname{Presum}+\sum_{x=l}^{mid}f_x\cdot g_{y-x} \]

\(F\)\(l\sim mid\) 项和 \(G\)\(1\sim r-l+1\) 项卷起来,结果再加到 \(F\) 里。

注意默认 \(F_0=1\).

时间复杂度 \(O(n\log^2n)\).

record

看了代码感觉还是可以理解的。


P4239 任意模数多项式乘法逆

假设已经求出 \(G'\) 满足 \(\displaystyle F(x)\times G'(x)\equiv1\space(\operatorname{mod}x^{\lfloor\frac{n}{2}\rfloor})\).

\[(G(x)-G'(x))^2\equiv0\space(\operatorname{mod}x^n) \]

\[F(x)G^2(x)-F(x)G'^2(x)-2G(x)G'(x)F(x)\equiv0 \]

\[G(x)-2G'(x)-F(x)G'^2(x)\equiv0 \]

\[G(x)\equiv G'(x)\times(2-F(x)G'(x)) \]

其实和 NTT 版本的是一样的。

也就是计算 \(H=F\times G'\),取反然后在常数项 \(+2\).

有一个东西是卷积的过程中对三模数做 CRT,其他情况下对给定模数直接做即可。

record

posted @ 2023-08-06 19:59  SError  阅读(24)  评论(0编辑  收藏  举报