多项式的各种操作(逆元,除法,取模,开根,对数,exp,多点求值,插值,牛顿迭代法)

多项式逆元

已知 A ( x ) A(x) A(x),求 A A A的逆元 B ( x ) B(x) B(x),使得 A ( x ) × B ( x ) = 1   ( m o d   x n ) A(x)\times B(x)=1\ (mod\ x^n) A(x)×B(x)=1 (mod xn)
如果 n = 1 n=1 n=1,则 A − 1 A^{-1} A1即为常数项的逆元

假设已经求出 A ( x ) A(x) A(x) ( m o d   x ⌈ n 2 ⌉ ) (mod\ x^{\lceil \frac n 2 \rceil}) (mod x2n)的逆元 B 2 ( x ) B_2(x) B2(x)
A ( x ) × B 2 ( x ) = 1   ( m o d   x ⌈ n 2 ⌉ ) A ( x ) × B ( x ) = 1   ( m o d   x n ) ⟹ A ( x ) × B ( x ) = 1   ( m o d   x ⌈ n 2 ⌉ ) 两 式 相 减 , 得 B ( x ) − B 2 ( x ) = 0   ( m o d   x ⌈ n 2 ⌉ ) ∴   B ( x ) − B 2 ( x ) 的 x 1 到 x ⌈ n 2 ⌉ − 1 的 系 数 都 为 0 ∴ 此 式 平 方 后 的 x 1 到 x n − 1 的 系 数 都 为 0 ∴   ( B ( x ) − B 2 ( x ) ) 2 = 0   ( m o d   x n ) ⟹ B 2 ( x ) − 2 B ( x ) B 2 ( x ) + B 2 2 ( x ) = 0   ( m o d   x n ) 两 边 同 时 乘 以 A ( x ) , 得 A ( x ) B 2 ( x ) − 2 A ( x ) B ( x ) B 2 ( x ) + A ( x ) B 2 2 ( x ) = 0   ( m o d   x n ) ⟹ B ( x ) − 2 B 2 ( x ) + A ( x ) B 2 2 ( x ) = 0   ( m o d   x n ) ⟹ B ( x ) = 2 B 2 ( x ) − A ( x ) B 2 2 ( x )   ( m o d   x n ) \begin{array}{ll} A(x)\times B_2(x)=1\ (mod\ x^{\lceil \frac n 2 \rceil })\\\\ A(x)\times B(x)=1\ (mod\ x^n) \Longrightarrow A(x)\times B(x)=1\ (mod\ x^{\lceil \frac n 2 \rceil})\\\\ 两式相减,得 B(x)-B_2(x)=0\ (mod\ x^{\lceil \frac n 2 \rceil })\\\\ \therefore\ B(x)-B_2(x) 的x^1到x^{\lceil \frac n 2 \rceil -1}的系数都为0\\\\ \therefore 此式平方后的x^1到x^{n -1}的系数都为0\\\\ \therefore\ (B(x)-B_2(x))^2=0\ (mod\ x^n) \Longrightarrow B^2(x)-2B(x)B_2(x)+{B_2}^2(x)=0\ (mod\ x^n)\\\\ 两边同时乘以A(x),得 A(x)B^2(x)-2A(x)B(x)B_2(x)+A(x){B_2}^2(x)=0\ (mod\ x^n)\\\\ \Longrightarrow B(x)-2B_2(x)+A(x){B_2}^2(x)=0\ (mod\ x^n)\\\\ \Longrightarrow B(x)=2B_2(x)-A(x){B_2}^2(x)\ (mod\ x^n)\\\\ \end{array} A(x)×B2(x)=1 (mod x2n)A(x)×B(x)=1 (mod xn)A(x)×B(x)=1 (mod x2n),B(x)B2(x)=0 (mod x2n) B(x)B2(x)x1x2n10x1xn10 (B(x)B2(x))2=0 (mod xn)B2(x)2B(x)B2(x)+B22(x)=0 (mod xn)A(x),A(x)B2(x)2A(x)B(x)B2(x)+A(x)B22(x)=0 (mod xn)B(x)2B2(x)+A(x)B22(x)=0 (mod xn)B(x)=2B2(x)A(x)B22(x) (mod xn)

void Inverse(const int A[],int B[],int deg)
{
    if(deg==1)
    {
        B[0]=PowMod(A[0],MOD-2);
        B[1]=0;//特别注意!!
        return;
    }
    static int A0[MAXN];
    Inverse(A,B,(deg+1)/2);
    int len=1;
    for(;len<deg*2-1;len<<=1);
    for(int i=0;i<deg;i++)A0[i]=A[i];
    for(int i=deg;i<len;i++)A0[i]=B[i]=0;
    NTT(A0,len,1);NTT(B,len,1);
    for(int i=0;i<len;i++)
        B[i]=1LL*B[i]*((2LL-1LL*A0[i]*B[i]%MOD+MOD)%MOD)%MOD;
    NTT(B,len,-1);
    for(int i=deg;i<len;i++)B[i]=0;
}

多项式除法及取模

已知 A ( x ) A(x) A(x), B ( x ) B(x) B(x),求 C ( x ) C(x) C(x), R ( x ) R(x) R(x),使得 A ( x ) = B ( x ) × C ( x ) + R ( x ) A(x)=B(x)\times C(x) +R(x) A(x)=B(x)×C(x)+R(x)
A A A最高次项为 x n x^n xn B B B最高次项为 x m x^m xm,则 C C C的最高次项为 x n − m x^{n-m} xnm R R R的最高次项为 x m − 1 x^{m-1} xm1
观察发现 x n A ( 1 x ) x^nA(\frac 1 x) xnA(x1)相当于把 A A A的系数翻转,记为 A r ( x ) A^r(x) Ar(x)
进行一系列变换
A ( 1 x ) = B ( 1 x ) C ( 1 x ) + R ( 1 x ) x n A ( 1 x ) = x n B ( 1 x ) C ( 1 x ) + x n R ( 1 x ) A r ( x ) = x m B ( 1 x )   x n − m C ( 1 x ) + x n − m + 1 x m − 1 R ( 1 x ) A r ( x ) = B r ( x ) C r ( x ) + x n − m + 1 R r ( x ) A r ( x ) = B r ( x ) C r ( x )   ( m o d   x n − m + 1 ) C r ( x ) = A r ( x ) B r ( x ) − 1   ( m o d   x n − m + 1 ) 即 先 求 出 B r ( x ) 的 逆 元 , 计 算 出 C r ( x ) , 翻 转 系 数 得 到 C ( x ) 再 将 C ( x ) 代 入 原 式 R ( x ) = A ( x ) − B ( x ) C ( x ) 即 求 出 R ( x ) \begin{array}{ll} A(\frac 1 x)=B(\frac 1 x)C(\frac 1 x)+R(\frac 1 x)\\\\ x^nA(\frac 1 x)=x^nB(\frac 1 x)C(\frac 1 x)+x^nR(\frac 1 x)\\\\ A^r(x)=x^mB(\frac 1 x)\ x^{n-m}C(\frac 1 x)+x^{n-m+1}x^{m-1}R(\frac 1 x)\\\\ A^r(x)=B^r(x)C^r(x)+x^{n-m+1}R^r(x)\\\\ A^r(x)=B^r(x)C^r(x)\space (mod \space x^{n-m+1})\\\\ C^r(x)=A^r(x)B^r(x)^{-1}\ (mod\ x^{n-m+1})\\\\ 即先求出B^r(x)的逆元,计算出C^r(x),翻转系数得到C(x)\\\\ 再将C(x)代入原式\\\\ R(x)=A(x)-B(x)C(x)\\\\ 即求出R(x)\\\\ \end{array} A(x1)=B(x1)C(x1)+R(x1)xnA(x1)=xnB(x1)C(x1)+xnR(x1)Ar(x)=xmB(x1) xnmC(x1)+xnm+1xm1R(x1)Ar(x)=Br(x)Cr(x)+xnm+1Rr(x)Ar(x)=Br(x)Cr(x) (mod xnm+1)Cr(x)=Ar(x)Br(x)1 (mod xnm+1)Br(x)Cr(x)C(x)C(x)R(x)=A(x)B(x)C(x)R(x)

void Module(int A[],int len1,const int B[],int len2)
{
    static int A0[MAXN*3],B0[MAXN*3],iB0[MAXN*3],C[MAXN*3];
    if(len1<len2)return;
    for(int i=0;i<len1;i++)A0[i]=A[len1-i-1];
    for(int i=0;i<len2;i++)B0[i]=B[len2-i-1];
    Inverse(B0,iB0,len1-len2+1);
    Multiply(A0,len1,iB0,len1-len2+1,C);
    for(int i=len1-len2+1;i<2*len1-len2;i++)C[i]=0;
    reverse(C,C+len1-len2+1);
    Multiply(C,len1-len2+1,B,len2,C);
    for(int i=0;i<len1;i++)A[i]=(A[i]-C[i]+MOD)%MOD;
}
多项式取模应用

用于优化常系数线性递推(把大部分矩阵乘法从 O ( n 3 ) O(n^3) O(n3)优化成 O ( n   l o g n ) O(n\ logn) O(n logn)
详见【CodeChef RNG】Random Number Generator

多项式开根

已知 A ( x ) A(x) A(x),求 B ( x ) B(x) B(x)使得, A ( x ) = B 2 ( x )   ( m o d   x n ) A(x)=B^2(x)\ (mod\ x^n) A(x)=B2(x) (mod xn)

设已经求得 B 2 ( x ) B_2(x) B2(x)使得, A ( x ) = B 2 2 ( x )   ( m o d   x ⌈ n 2 ⌉ ) A(x)={B_2}^2(x)\ (mod\ x^{\lceil \frac n 2 \rceil}) A(x)=B22(x) (mod x2n)
∵ A ( x ) = B 2 ( x )   ( m o d   x n ) ⟹ A ( x ) = B 2 ( x )   ( m o d   x ⌈ n 2 ⌉ ) 又 ∵ A ( x ) = B 2 2 ( x )   ( m o d   x ⌈ n 2 ⌉ ) ∴ B 2 ( x ) = B 2 2 ( x )   ( m o d   x ⌈ n 2 ⌉ ) B 2 ( x ) − B 2 2 ( x ) = 0   ( m o d   x ⌈ n 2 ⌉ ) ( B 2 ( x ) − B 2 2 ( x ) ) 2 = 0   ( m o d   x n ) ( B 2 ( x ) + B 2 2 ( x ) ) 2 = 4 B 2 ( x ) B 2 2 ( x )   ( m o d   x n ) B 2 ( x ) + B 2 2 ( x ) = 2 B ( x ) B 2 ( x )   ( m o d   x n ) B ( x ) = A ( x ) + B 2 2 ( x ) 2 B 2 ( x )   ( m o d   x n ) \begin{array}{ll} \because A(x)=B^2(x)\ (mod\ x^n) \Longrightarrow A(x)=B^2(x)\ (mod\ x^{\lceil \frac n 2 \rceil})\\\\ 又\because A(x)={B_2}^2(x)\ (mod\ x^{\lceil \frac n 2 \rceil})\\\\ \therefore B^2(x)={B_2}^2(x)\ (mod\ x^{\lceil \frac n 2 \rceil})\\\\ B^2(x)-{B_2}^2(x)=0\ (mod\ x^{\lceil \frac n 2 \rceil})\\\\ \left(B^2(x)-{B_2}^2(x)\right)^2=0\ (mod\ x^n)\\\\ \left(B^2(x)+{B_2}^2(x)\right)^2=4B^2(x){B_2}^2(x)\ (mod\ x^n)\\\\ B^2(x)+{B_2}^2(x)=2B(x){B_2}(x)\ (mod\ x^n)\\\\ B(x)=\frac {A(x)+{B_2}^2(x)} {2{B_2}(x)}\ (mod\ x^n) \end{array} A(x)=B2(x) (mod xn)A(x)=B2(x) (mod x2n)A(x)=B22(x) (mod x2n)B2(x)=B22(x) (mod x2n)B2(x)B22(x)=0 (mod x2n)(B2(x)B22(x))2=0 (mod xn)(B2(x)+B22(x))2=4B2(x)B22(x) (mod xn)B2(x)+B22(x)=2B(x)B2(x) (mod xn)B(x)=2B2(x)A(x)+B22(x) (mod xn)

void Sqrt(const int A[],int B[],int n)
{
	if(n==1)
	{
		B[0]=sqrt(A[0]);
		return;
	}
	Sqrt(A,B,(n+1)/2);
	static int A0[MAXN*3],B0[MAXN*3],iB0[MAXN*3];
	for(int i=0;i<n;i++)B0[i]=2LL*B[i]%MOD;
	Inverse(B0,iB0,n);
	Multiply(B,n,B,n,A0);
	for(int i=n;i<n*2;i++)A0[i]=0;
	for(int i=0;i<n;i++)A0[i]=(A[i]+A0[i])%MOD;
	Multiply(iB0,n,A0,n,B);
	for(int i=n;i<n*2;i++)B[i]=0;
}

多项式对数

已知 A ( x ) A(x) A(x),求 B ( x ) B(x) B(x),使得 e B ( x ) = A ( x )   ( m o d   x n ) e^{B(x)}=A(x)\ (mod\ x^n) eB(x)=A(x) (mod xn),即 l n   A ( x ) = B ( x )   ( m o d   x n ) ln\ A(x)=B(x)\ (mod\ x^n) ln A(x)=B(x) (mod xn)
思路就是先求导再积分(虽然我没学过积分,但至少直到积分为求导的逆过程,对这个函数来说,求导再积分等于啥都没做)
l n   A ( x ) = ∫ ( l n   A ( x ) ) ′ = ∫ A ′ ( x ) A ( x ) ln\ A(x)=\int(ln\ A(x))&#x27;=\int \frac {A&#x27;(x)} {A(x)} ln A(x)=(ln A(x))=A(x)A(x)
导数公式:
A ′ ( x i − 1 ) = A ( x i ) × i A&#x27;(x^{i-1})=A(x^i)\times i A(xi1)=A(xi)×i
积分公式:
∫ A ( x i ) = A ( x i − 1 ) i \int A(x^i)=\frac {A(x^{i-1})} i A(xi)=iA(xi1)

void Derivation(const int A[],int B[],int n)
{
	for(int i=1;i<n;i++)
		B[i-1]=1LL*A[i]*i%MOD;
	B[n-1]=0;
}
void Integral(const int A[],int B[],int n)
{
	for(int i=n;i>=1;i--)
		B[i]=1LL*A[i-1]*PowMod(i,MOD-2)%MOD;
	B[0]=0;
}
void Logarithm(const int A[],int B[],int n)//需保证A[0]=1
{
    static int iA[MAXN*3],A1[MAXN*3];
    Inverse(A,iA,n);
    Derivation(A,A1,n);
    Multiply(A1,n-1,iA,n,A1);
    Integral(A1,B,n);
}
多项式对数应用

有一个公式: e x = ∑ x i i ! e^x=\sum \frac {x^i} {i!} ex=i!xi
当计算出某个所求答案为 B ( x ) B(x) B(x),且知道 A ( x ) = ∑ B ( x ) i i ! A(x)=\sum \frac {{B(x)}^i} {i!} A(x)=i!B(x)i,则 e B ( x ) = A ( x ) e^{B(x)}=A(x) eB(x)=A(x)
如果 A ( x ) A(x) A(x)很好求,则求出 A ( x ) A(x) A(x),再用多项式对数求出 B ( x ) B(x) B(x)

多项式exp

直接推需要分治NTT,写起来有些恶心,于是去看牛顿迭代法的推法吧(在后面)。

void Exponential(const int A[],int B[],int n)//需保证A[0]=0;
{
    if(n==1)
    {
        B[0]=1;
        return;
    }
    Exponential(A,B,(n+1)/2);
    static int A0[MAXN*3];
    Logarithm(B,A0,n);
    for(int i=0;i<n;i++)A0[i]=(MOD-A0[i]+A[i])%MOD;
    A0[0]=(A0[0]+1)%MOD;
    Multiply(B,n,A0,n,B);
    for(int i=n;i<n*2;i++)B[i]=0;
}

多项式 超级 快速幂

已知 A ( x ) A(x) A(x) k k k,求 B ( x ) B(x) B(x),使得 A ( x ) k = B ( x )   ( m o d   x n ) A(x)^k=B(x)\ (mod\ x^n) A(x)k=B(x) (mod xn)
B ( x ) = A ( x ) k = e k   l n   A ( x ) B(x)=A(x)^k=e^{k\ ln\ A(x)} B(x)=A(x)k=ek ln A(x)

void Power(const int A[],int B[],int n,int k)
{
	static int A0[MAXN*3];
	for(int i=0;i<n;i++)A0[i]=0;
	Logarithm(A,A0,n);
	for(int i=0;i<n;i++)A0[i]=1LL*A0[i]*k%MOD;
	Exponential(A0,B,n);
}

多项式多点求值

给一个多项式 A A A,一个数组 X [ i ]   ( 1 ≤ i ≤ m ) X[i]\ (1\leq i\leq m) X[i] (1im),求所有 A ( X [ i ] ) A(X[i]) A(X[i])的值。

P 0 ( x ) = ∏ i = 1 m / 2 ( x − X [ i ] ) P_0(x)=\prod_{i=1}^{m/2}(x-X[i]) P0(x)=i=1m/2(xX[i]) P 1 ( x ) = ∏ i = m / 2 + 1 m ( x − X [ i ] ) P_1(x)=\prod_{i=m/2+1}^m(x-X[i]) P1(x)=i=m/2+1m(xX[i])

A ( x ) = D 0 ( x ) P 0 ( x ) + A 0 ( x ) A ( x ) = D 1 ( x ) P 1 ( x ) + A 1 ( x ) \begin{array}{ll} A(x)=D_0(x)P_0(x)+A_0(x)\\\\ A(x)=D_1(x)P_1(x)+A_1(x) \end{array} A(x)=D0(x)P0(x)+A0(x)A(x)=D1(x)P1(x)+A1(x)
A 0 ( x ) = A ( x )   m o d   P 0 ( x ) A_0(x)=A(x)\ mod\ P_0(x) A0(x)=A(x) mod P0(x) A 1 ( x ) = A ( x )   m o d   P 1 ( x ) A_1(x)=A(x)\ mod\ P_1(x) A1(x)=A(x) mod P1(x)
如果将1~m/2的X[i]代入, P 0 ( X [ i ] ) = 0 P_0(X[i])=0 P0(X[i])=0,则 D 0 ( x ) P 0 ( x ) D_0(x)P_0(x) D0(x)P0(x)与结果无关,答案只与 A 0 ( x ) A_0(x) A0(x)有关,且 A 0 A_0 A0的长度缩短为 A A A的一半,所以可以进行递归计算。

实现时,需用分治NTT预处理多项式P,即每次分成两半计算,然后再把两半用NTT乘起来
P需用类似于线段树的方式存储,并给每个结点开一整段内存空间。
求值时的 A 0 A_0 A0也是这样存储。

int *P[MAXN*4],buf[MAXN*MAXLOG*5],*bufit=buf;

void CalcP(int i,int X[],int L,int R)
{
    if(L==R)
    {
        P[i]=bufit;bufit+=2;
        P[i][1]=1;P[i][0]=(MOD-X[L])%MOD;
        return;
    }
    int mid=(L+R)/2;
    CalcP(i*2,X,L,mid);
    CalcP(i*2+1,X,mid+1,R);
    P[i]=bufit;bufit+=(R-L+2);
    Multiply(P[i*2],mid-L+2,P[i*2+1],R-mid+1,P[i]);
}
void Evaluation(const int A[],int len1,int i,int L,int R,int ans[])
{
    int *A0=bufit;bufit+=len1;
    for(int i=0;i<len1;i++)A0[i]=A[i];
    Module(A0,len1,P[i],R-L+2);
    if(L==R)
    {
        ans[L]=A0[0];
        return;
    }
    int mid=(L+R)/2;
    Evaluation(A0,min(R-L+1,len1),i*2,L,mid,ans);
    Evaluation(A0,min(R-L+1,len1),i*2+1,mid+1,R,ans);
}

多项式插值

给出n个点 ( X [ i ] , Y [ i ] ) (X[i],Y[i]) (X[i],Y[i]),求出一个多项式 A ( x ) A(x) A(x),满足 A ( X [ i ] ) = Y [ i ] A(X[i])=Y[i] A(X[i])=Y[i]

利用拉格朗日插值公式:对于一个 i i i
∏ j = 1 , j ̸ = i n x − X [ j ] X [ i ] − X [ j ] \prod_{j=1,j\not=i}^n \frac {x-X[j]} {X[i]-X[j]} j=1,j̸=inX[i]X[j]xX[j]
观察这个式子,发现它在 x = X [ i ] x=X[i] x=X[i]时为1,取其它 X [ ] X[] X[]中的值时为0
A A A就可以表示为 A ( x ) = ∑ i = 1 n Y [ i ] × ∏ j = 1 , j ̸ = i n x − X [ j ] X [ i ] − X [ j ] A(x)=\sum_{i=1}^nY[i]\times \prod_{j=1,j\not=i}^n \frac {x-X[j]} {X[i]-X[j]} A(x)=i=1nY[i]×j=1,j̸=inX[i]X[j]xX[j]
转化为
A ( x ) = ∑ i = 1 n Y [ i ] ∏ j = 1 , j ̸ = i n X [ i ] − X [ j ] ∏ j = 1 , j ̸ = i n x − X [ j ] A(x)=\sum_{i=1}^n\frac {Y[i]} {\prod_{j=1,j\not=i}^nX[i]-X[j]}\prod_{j=1,j\not=i}^nx-X[j] A(x)=i=1nj=1,j̸=inX[i]X[j]Y[i]j=1,j̸=inxX[j]
P ( x ) = ∏ i = 1 n ( x − X [ i ] ) P(x)=\prod_{i=1}^{n}(x-X[i]) P(x)=i=1n(xX[i]),记 P i ( x ) P_i(x) Pi(x) P i ( x ) = ∏ j = 1 , j ̸ = i n x − X [ j ] = P ( x ) x − X [ i ] P_i(x)=\prod_{j=1,j\not=i}^nx-X[j]=\frac {P(x)} {x-X[i]} Pi(x)=j=1,j̸=inxX[j]=xX[i]P(x)
P ( x ) = ( x − X [ i ] ) P i ( x ) P(x)=(x-X[i])P_i(x) P(x)=(xX[i])Pi(x),对 P ( x ) P(x) P(x)求导 (初中生自己去查)
P ′ ( x ) = P i ( x ) + ( x − X [ i ] ) P i ′ ( x ) P&#x27;(x)=P_i(x)+(x-X[i]){P_i}&#x27;(x) P(x)=Pi(x)+(xX[i])Pi(x)
x = x i x=x_i x=xi,发现 P i ( x i ) = P ′ ( x i ) P_i(x_i)=P&#x27;(x_i) Pi(xi)=P(xi)
代入原来的 A ( x ) A(x) A(x)
A ( x ) = ∑ i = 1 n Y [ i ] P i ( X [ i ] ) P ( x ) x − X [ i ] A(x)=\sum_{i=1}^n \frac {Y[i]} {P_i(X[i])} \frac {P(x)} {x-X[i]} A(x)=i=1nPi(X[i])Y[i]xX[i]P(x)
A ( x ) = ∑ i = 1 n Y [ i ] P ′ ( X [ i ] ) P ( x ) x − X [ i ] A(x)=\sum_{i=1}^n \frac {Y[i]} {P&#x27;(X[i])} \frac {P(x)} {x-X[i]} A(x)=i=1nP(X[i])Y[i]xX[i]P(x)
这个式子可以分治算出:
首先,分治FFT预处理出 P P P(同多项式多点求值),求出导数,然后用多点求值的方法求出所有 P ′ ( X [ i ] ) P&#x27;(X[i]) P(X[i])
P 0 ( x ) = ∏ i = 1 m / 2 ( x − X [ i ] ) P_0(x)=\prod_{i=1}^{m/2}(x-X[i]) P0(x)=i=1m/2(xX[i]) P 1 ( x ) = ∏ i = m / 2 + 1 m ( x − X [ i ] ) P_1(x)=\prod_{i=m/2+1}^m(x-X[i]) P1(x)=i=m/2+1m(xX[i])(这些已在预处理中求出)
A ( x ) A(x) A(x)进行分治,设 A 0 A_0 A0 A 1 A_1 A1 A 0 ( x ) = ∑ i = 1 n / 2 Y [ i ] P ′ ( X [ i ] ) P ( x ) x − X [ i ] A_0(x)=\sum_{i=1}^{n/2} \frac {Y[i]} {P&#x27;(X[i])} \frac {P(x)} {x-X[i]} A0(x)=i=1n/2P(X[i])Y[i]xX[i]P(x) A 1 ( x ) = ∑ i = n / 2 + 1 n Y [ i ] P ′ ( X [ i ] ) P ( x ) x − X [ i ] A_1(x)=\sum_{i=n/2+1}^{n} \frac {Y[i]} {P&#x27;(X[i])} \frac {P(x)} {x-X[i]} A1(x)=i=n/2+1nP(X[i])Y[i]xX[i]P(x)
A ( x ) = A 0 ( x ) P 1 ( x ) + A 1 ( x ) P 0 ( x ) A(x)=A_0(x)P_1(x)+A_1(x)P_0(x) A(x)=A0(x)P1(x)+A1(x)P0(x)
递归计算即可,而且 A 0 A_0 A0 A 1 A_1 A1不需要像多项式多点求值一样单独开空间,直接在原来的 A ( x ) A(x) A(x)数组上用即可。

void Interpolate(const int X[],const int Y[],int i,int L,int R,int A[])
{
    if(L==R)
    {
        A[0]=1LL*Y[L]*PowMod(Pi[L],MOD-2)%MOD;
        return;
    }
    static int res1[MAXN],res2[MAXN];
    int mid=(L+R)/2,len1=mid-L+1,len2=R-mid;
    Interpolate(X,Y,i*2,L,mid,A);
    Interpolate(X,Y,i*2+1,mid+1,R,A+len1);
    Multiply(A,len1,P[i*2+1],len2+1,res1);
    Multiply(A+len1,len2,P[i*2],len1+1,res2);
    for(int i=0;i<R-L+1;i++)A[i]=(res1[i]+res2[i])%MOD;
}

牛顿迭代法

普通函数牛顿迭代法

求函数 g ( x ) g(x) g(x)的零点
先随便找一个 x 0 x_0 x0,利用 x 0 x_0 x0推出一个更接近零点的 x 1 x_1 x1,继续递推。。。无限逼近
方法:在 x 0 x_0 x0做x轴垂线,与函数交于 ( x 0 , g ( x ) ) (x_0,g(x)) (x0,g(x)),过这一点做函数的切线,切线与x轴的交点即为 x 1 x_1 x1,即 x i + 1 = x i − g ( x ) g ′ ( x ) x_{i+1}=x_i-\frac {g(x)} {g&#x27;(x)} xi+1=xig(x)g(x)

多项式牛顿迭代法

给定函数 G ( x ) G(x) G(x)
求多项式 F ( x ) F(x) F(x),使得 G ( F ( x ) ) ≡ 0   ( m o d   x n ) G(F(x))\equiv 0\space (mod\space x^n) G(F(x))0 (mod xn)

类比普通函数多项式推导

倍增求解,设 F t ( x ) F_t(x) Ft(x)满足 G ( F t ( x ) ) ≡ 0   ( m o d   x ⌈ n 2 ⌉ ) G(F_t(x))\equiv 0 \space (mod \space x^{\lceil \frac n 2 \rceil}) G(Ft(x))0 (mod x2n),且 F t ( x ) F_t(x) Ft(x)已求出。
试图求出 F t + 1 ( x ) F_{t+1}(x) Ft+1(x)满足 G ( F t + 1 ( x ) ) ≡ 0   ( m o d   x n ) G(F_{t+1}(x))\equiv 0 \space (mod \space x^{n}) G(Ft+1(x))0 (mod xn)
F t + 1 ( x ) = F t ( x ) − G ( F t ( x ) ) G ′ ( F t ( x ) ) F_{t+1}(x)=F_t(x)-\frac {G(F_t(x))} {G&#x27;(F_t(x))} Ft+1(x)=Ft(x)G(Ft(x))G(Ft(x))

泰勒公式证明

G ( F t + 1 ( x ) ) G(F_{t+1}(x)) G(Ft+1(x))用泰勒公式在 F t ( x ) F_t(x) Ft(x)展开

G ( F t + 1 ( x ) ) = G ( F t ( x ) ) 0 ! + G ′ ( F t ( x ) ) 1 ! ( F t + 1 ( x ) − F t ( x ) ) + G ′ ′ ( F t ( x ) ) 2 ! ( F t + 1 ( x ) − F t ( x ) ) 2 + . . . G(F_{t+1}(x))=\frac {G(F_t(x))} {0!}+\frac {G&#x27;(F_t(x))} {1!}(F_{t+1}(x)-F_t(x))+\frac {G&#x27;&#x27;(F_t(x))} {2!}(F_{t+1}(x)-F_t(x))^2+... G(Ft+1(x))=0!G(Ft(x))+1!G(Ft(x))(Ft+1(x)Ft(x))+2!G(Ft(x))(Ft+1(x)Ft(x))2+...

因为 F t ( x ) F_t(x) Ft(x) F t + 1 ( x ) F_{t+1}(x) Ft+1(x)的前半截的系数是一样的(最终 F ( x ) F(x) F(x)是唯一的),所以它们的差平方后在 x n x^n xn下以前的项都为0
因为 G ′ ′ ( F t ( x ) ) 2 ! ( F t + 1 ( x ) − F t ( x ) ) 2 \frac {G&#x27;&#x27;(F_t(x))} {2!}(F_{t+1}(x)-F_t(x))^2 2!G(Ft(x))(Ft+1(x)Ft(x))2以及之后的项, m o d   x n mod \space x^{n} mod xn都为0,所以只取前面两项。

G ( F t + 1 ( x ) ) = G ( F t ( x ) ) + G ′ ( F t ( x ) ) ( F t + 1 ( x ) − F t ( x ) ) G(F_{t+1}(x))={G(F_t(x))}+{G&#x27;(F_t(x))}(F_{t+1}(x)-F_t(x)) G(Ft+1(x))=G(Ft(x))+G(Ft(x))(Ft+1(x)Ft(x))

F t + 1 ( x ) = F t ( x ) − G ( F t ( x ) ) G ′ ( F t ( x ) ) F_{t+1}(x)=F_t(x)-\frac {G(F_t(x))} {G&#x27;(F_t(x))} Ft+1(x)=Ft(x)G(Ft(x))G(Ft(x))

用牛顿迭代法解释多项式操作

多项式逆元

已知多项式 A ( x ) A(x) A(x),求多项式 B ( x ) B(x) B(x),使得 A × B ≡ 1   ( m o d   x n ) A\times B\equiv 1\space (mod \space x^n) A×B1 (mod xn)(即只保留 x n x^n xn以前的项)
用牛顿迭代法,求: A × B − 1 ≡ 0   ( m o d   x n ) A\times B -1 \equiv 0\space (mod\space x^n) A×B10 (mod xn)
B t + 1 ( x ) = B t ( x ) − A ( x ) B t ( x ) − 1 A ( x ) = B t ( x ) − ( A ( x ) B t ( x ) − 1 ) B t ( x ) = 2 B t ( x ) + A ( x ) B t 2 ( x ) B_{t+1}(x)=B_t(x)-\frac {A(x)B_t(x)-1} {A(x)}\\=B_t(x)-(A(x)B_t(x)-1)B_t(x)\\=2B_t(x)+A(x){B_t}^2(x) Bt+1(x)=Bt(x)A(x)A(x)Bt(x)1=Bt(x)(A(x)Bt(x)1)Bt(x)=2Bt(x)+A(x)Bt2(x)
即可以递归求解

小性质: B t ( x ) B_t(x) Bt(x) B t + 1 ( x ) B_{t+1}(x) Bt+1(x)的前 x n / 2 x^{n/2} xn/2项相同,自己臆想。。
公式第二行解释:
除以 A ( x ) A(x) A(x) x n x^n xn本应该等于乘以 B t + 1 ( x ) B_{t+1}(x) Bt+1(x),这里把除以 A ( x ) A(x) A(x)替换为 B t ( x ) B_t(x) Bt(x)是因为 ( A ( x ) B t ( x ) − 1 ) (A(x)B_t(x)-1) (A(x)Bt(x)1) x n / 2 x^{n/2} xn/2以内的系数都为0,而最后结果只取前 x n x^n xn位,所乘的逆元只有前 x n / 2 x^{n/2} xn/2项有用,而 B t ( x ) B_t(x) Bt(x) B t + 1 ( x ) B_{t+1}(x) Bt+1(x)在前 x n / 2 x^{n/2} xn/2项是相同的,所以可以用 B t ( x ) B_t(x) Bt(x)代替 B t + 1 ( x ) B_{t+1}(x) Bt+1(x)

多项式exp

已知 A ( x ) A(x) A(x),求 B ( x ) B(x) B(x),满足 e A ( x ) = B ( x )   ( m o d   x n ) e^{A(x)}=B(x)\ (mod\ x^n) eA(x)=B(x) (mod xn)
e A ( x ) = B ( x ) A ( x ) = ln ⁡ B ( x ) ln ⁡ B ( x ) − A ( x ) = 0 B t + 1 ( x ) = B t ( x ) − ln ⁡ B t ( x ) − A ( x ) 1 B t ( x ) B t + 1 ( x ) = B t ( x ) ( 1 − ln ⁡ B t ( x ) + A ( x ) ) \begin{array}{ll} e^{A(x)}=B(x)\\\\ A(x)=\ln B(x)\\\\ \ln B(x)-A(x)=0\\\\ B_{t+1}(x)=B_t(x)-\frac{\ln B_t(x)-A(x)}{\frac{1}{B_t(x)}}\\\\ B_{t+1}(x)=B_t(x)(1-\ln B_t(x)+A(x)) \end{array} eA(x)=B(x)A(x)=lnB(x)lnB(x)A(x)=0Bt+1(x)=Bt(x)Bt(x)1lnBt(x)A(x)Bt+1(x)=Bt(x)(1lnBt(x)+A(x))

void Exponential(const int A[],int B[],int n)//需保证A[0]=0;
{
    if(n==1)
    {
        B[0]=1;
        return;
    }
    Exponential(A,B,(n+1)/2);
    static int A0[MAXN*3];
    Logarithm(B,A0,n);
    for(int i=0;i<n;i++)A0[i]=(MOD-A0[i]+A[i])%MOD;
    A0[0]=(A0[0]+1)%MOD;
    Multiply(B,n,A0,n,B);
    for(int i=n;i<n*2;i++)B[i]=0;
}

总模板

只贴当前已完成的
各种题目代码混合,有可能有函数接口不匹配的问题。。。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=100005,MAXLOG=20,MOD=998244353,ROOT=3;

int PowMod(int a,int b)
{
    int res=1;
    for(;b;b>>=1,a=1LL*a*a%MOD)
        if(b&1)
            res=1LL*res*a%MOD;
    return res;
}
int W[2][MAXLOG][MAXN*6],iW[MAXLOG][MAXN*6];
void InitNTT()
{
    for(int i=0;(1<<i)<MAXN*6;i++)
    {
        W[0][i][0]=W[1][i][0]=1;
        W[0][i][1]=PowMod(ROOT,(MOD-1)/(1<<i));
        W[1][i][1]=PowMod(W[0][i][1],MOD-2);
        for(int j=2;j<(1<<i);j++)
        {
            W[0][i][j]=1LL*W[0][i][j-1]*W[0][i][1]%MOD;
            W[1][i][j]=1LL*W[1][i][j-1]*W[1][i][1]%MOD;
        }
    }
}
void NTT(int A[],int n,int mode)
{
    for(int i=0,j=0;i<n;i++)
    {
        if(i<j)swap(A[i],A[j]);
        int k=n>>1;
        while(k&j)
            j^=k,k>>=1;
        j^=k;
    }
    mode=mode==1?0:1;
    for(int i=1,c=1;i<n;i<<=1,c++)
        for(int j=0;j<n;j+=(i<<1))
            for(int l=j,r=j+i;l<j+i;l++,r++)
            {
                int tmp=1LL*A[r]*W[mode][c][l-j]%MOD;
                A[r]=(A[l]-tmp+MOD)%MOD;
                A[l]=(A[l]+tmp)%MOD;
            }
    if(mode==1)
    {
        int invn=PowMod(n,MOD-2);
        for(int i=0;i<n;i++)
            A[i]=1LL*A[i]*invn%MOD;
    }
}

void Multiply(const int A[],int len1,const int B[],int len2,int C[])
{
    static int A0[MAXN*3],B0[MAXN*3];
    int len=1;
    for(;len<len1+len2-1;len<<=1);
    for(int i=0;i<len1;i++)A0[i]=A[i];
    for(int i=len1;i<len;i++)A0[i]=0;
    for(int i=0;i<len2;i++)B0[i]=B[i];
    for(int i=len2;i<len;i++)B0[i]=0;
    NTT(A0,len,1);NTT(B0,len,1);
    for(int i=0;i<len;i++)
        A0[i]=1LL*A0[i]*B0[i]%MOD;
    NTT(A0,len,-1);
    for(int i=0;i<len1+len2-1;i++)C[i]=A0[i];
}

void Inverse(const int A[],int B[],int deg)
{
    if(deg==1)
    {
        B[0]=PowMod(A[0],MOD-2);
        B[1]=0;
        return;
    }
    static int A0[MAXN];
    Inverse(A,B,(deg+1)/2);
    int len=1;
    for(;len<deg*2-1;len<<=1);
    for(int i=0;i<deg;i++)A0[i]=A[i];
    for(int i=deg;i<len;i++)A0[i]=B[i]=0;
    NTT(A0,len,1);NTT(B,len,1);
    for(int i=0;i<len;i++)
        B[i]=1LL*B[i]*((2LL-1LL*A0[i]*B[i]%MOD+MOD)%MOD)%MOD;
    NTT(B,len,-1);
    for(int i=deg;i<len;i++)B[i]=0;
}

void Module(int A[],int len1,const int B[],int len2)
{
    static int A0[MAXN*3],B0[MAXN*3],iB0[MAXN*3],C[MAXN*3];
    if(len1<len2)return;
    for(int i=0;i<len1;i++)A0[i]=A[len1-i-1];
    for(int i=0;i<len2;i++)B0[i]=B[len2-i-1];
    Inverse(B0,iB0,len1-len2+1);
    Multiply(A0,len1,iB0,len1-len2+1,C);
    for(int i=len1-len2+1;i<2*len1-len2;i++)C[i]=0;
    reverse(C,C+len1-len2+1);
    Multiply(C,len1-len2+1,B,len2,C);
    for(int i=0;i<len1;i++)A[i]=(A[i]-C[i]+MOD)%MOD;
}
void Derivation(const int A[],int B[],int n)
{
	for(int i=1;i<n;i++)
		B[i-1]=1LL*A[i]*i%MOD;
	B[n-1]=0;
}
void Integral(const int A[],int B[],int n)
{
	for(int i=n;i>=1;i--)
		B[i]=1LL*A[i-1]*PowMod(i,MOD-2)%MOD;
	B[0]=0;
}
void Logarithm(const int A[],int B[],int n)//需保证A[0]=1
{
    static int iA[MAXN*3],A1[MAXN*3];
    Inverse(A,iA,n);
    Derivation(A,A1,n);
    Multiply(A1,n-1,iA,n,A1);
    Integral(A1,B,n);
}
void Exponential(const int A[],int B[],int n)//需保证A[0]=0;
{
    if(n==1)
    {
        B[0]=1;
        return;
    }
    Exponential(A,B,(n+1)/2);
    static int A0[MAXN*3];
    Logarithm(B,A0,n);
    for(int i=0;i<n;i++)A0[i]=(MOD-A0[i]+A[i])%MOD;
    A0[0]=(A0[0]+1)%MOD;
    Multiply(B,n,A0,n,B);
    for(int i=n;i<n*2;i++)B[i]=0;
}
void Power(const int A[],int B[],int n,int k)
{
	static int A0[MAXN*3];
	for(int i=0;i<n;i++)A0[i]=0;
	Logarithm(A,A0,n);
	for(int i=0;i<n;i++)A0[i]=1LL*A0[i]*k%MOD;
	Exponential(A0,B,n);
}
void Sqrt(const int A[],int B[],int n)
{
	if(n==1)
	{
		B[0]=sqrt(A[0]);
		return;
	}
	Sqrt(A,B,(n+1)/2);
	static int A0[MAXN*3],B0[MAXN*3],iB0[MAXN*3];
	for(int i=0;i<n;i++)B0[i]=2LL*B[i]%MOD;
	Inverse(B0,iB0,n);
	Multiply(B,n,B,n,A0);
	for(int i=n;i<n*2;i++)A0[i]=0;
	for(int i=0;i<n;i++)A0[i]=(A[i]+A0[i])%MOD;
	Multiply(iB0,n,A0,n,B);
	for(int i=n;i<n*2;i++)B[i]=0;
}

int *P[MAXN*4],buf[MAXN*MAXLOG*6],*bufit=buf;
//P:线段树区间,区间为X区间的prod(x-xi)多项式
//buf:内存缓存,给P的空间
int dP[MAXN],Pi[MAXN];//dP:P的导数;Pi:dP代入X值得到的Y值

void CalcP(int i,int X[],int L,int R)
{
    if(L==R)
    {
        P[i]=bufit;bufit+=2;
        P[i][1]=1;P[i][0]=(MOD-X[L])%MOD;
        return;
    }
    int mid=(L+R)/2;
    CalcP(i*2,X,L,mid);
    CalcP(i*2+1,X,mid+1,R);
    P[i]=bufit;bufit+=(R-L+2);
    Multiply(P[i*2],mid-L+2,P[i*2+1],R-mid+1,P[i]);
}
void Evaluation(const int A[],int len1,int i,int L,int R,int ans[])
{
    int *A0=bufit;bufit+=len1;
    for(int i=0;i<len1;i++)A0[i]=A[i];
    Module(A0,len1,P[i],R-L+2);
    if(L==R)
    {
        ans[L]=A0[0];
        return;
    }
    int mid=(L+R)/2;
    Evaluation(A0,min(R-L+1,len1),i*2,L,mid,ans);
    Evaluation(A0,min(R-L+1,len1),i*2+1,mid+1,R,ans);
}
void Interpolate(const int X[],const int Y[],int i,int L,int R,int A[])
{
    if(L==R)
    {
        A[0]=1LL*Y[L]*PowMod(Pi[L],MOD-2)%MOD;
        return;
    }
    static int res1[MAXN],res2[MAXN];
    int mid=(L+R)/2,len1=mid-L+1,len2=R-mid;
    Interpolate(X,Y,i*2,L,mid,A);
    Interpolate(X,Y,i*2+1,mid+1,R,A+len1);
    Multiply(A,len1,P[i*2+1],len2+1,res1);
    Multiply(A+len1,len2,P[i*2],len1+1,res2);
    for(int i=0;i<R-L+1;i++)A[i]=(res1[i]+res2[i])%MOD;
}

int main()
{
    return 0;
}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值