多项式逆元
已知
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}
A−1即为常数项的逆元
假设已经求出
A
(
x
)
A(x)
A(x)在
(
m
o
d
x
⌈
n
2
⌉
)
(mod\ x^{\lceil \frac n 2 \rceil})
(mod x⌈2n⌉)的逆元
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 x⌈2n⌉)A(x)×B(x)=1 (mod xn)⟹A(x)×B(x)=1 (mod x⌈2n⌉)两式相减,得B(x)−B2(x)=0 (mod x⌈2n⌉)∴ B(x)−B2(x)的x1到x⌈2n⌉−1的系数都为0∴此式平方后的x1到xn−1的系数都为0∴ (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}
xn−m,
R
R
R的最高次项为
x
m
−
1
x^{m-1}
xm−1
观察发现
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) xn−mC(x1)+xn−m+1xm−1R(x1)Ar(x)=Br(x)Cr(x)+xn−m+1Rr(x)Ar(x)=Br(x)Cr(x) (mod xn−m+1)Cr(x)=Ar(x)Br(x)−1 (mod xn−m+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 x⌈2n⌉)
∵
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 x⌈2n⌉)又∵A(x)=B22(x) (mod x⌈2n⌉)∴B2(x)=B22(x) (mod x⌈2n⌉)B2(x)−B22(x)=0 (mod x⌈2n⌉)(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))'=\int \frac {A'(x)} {A(x)}
ln A(x)=∫(ln A(x))′=∫A(x)A′(x)
导数公式:
A
′
(
x
i
−
1
)
=
A
(
x
i
)
×
i
A'(x^{i-1})=A(x^i)\times i
A′(xi−1)=A(xi)×i
积分公式:
∫
A
(
x
i
)
=
A
(
x
i
−
1
)
i
\int A(x^i)=\frac {A(x^{i-1})} i
∫A(xi)=iA(xi−1)
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] (1≤i≤m),求所有 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(x−X[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(x−X[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̸=i∏nX[i]−X[j]x−X[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=1∑nY[i]×j=1,j̸=i∏nX[i]−X[j]x−X[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=1∑n∏j=1,j̸=inX[i]−X[j]Y[i]j=1,j̸=i∏nx−X[j]
设
P
(
x
)
=
∏
i
=
1
n
(
x
−
X
[
i
]
)
P(x)=\prod_{i=1}^{n}(x-X[i])
P(x)=∏i=1n(x−X[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̸=i∏nx−X[j]=x−X[i]P(x)
则
P
(
x
)
=
(
x
−
X
[
i
]
)
P
i
(
x
)
P(x)=(x-X[i])P_i(x)
P(x)=(x−X[i])Pi(x),对
P
(
x
)
P(x)
P(x)求导 (初中生自己去查)
P
′
(
x
)
=
P
i
(
x
)
+
(
x
−
X
[
i
]
)
P
i
′
(
x
)
P'(x)=P_i(x)+(x-X[i]){P_i}'(x)
P′(x)=Pi(x)+(x−X[i])Pi′(x)
取
x
=
x
i
x=x_i
x=xi,发现
P
i
(
x
i
)
=
P
′
(
x
i
)
P_i(x_i)=P'(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=1∑nPi(X[i])Y[i]x−X[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'(X[i])} \frac {P(x)} {x-X[i]}
A(x)=i=1∑nP′(X[i])Y[i]x−X[i]P(x)
这个式子可以分治算出:
首先,分治FFT预处理出
P
P
P(同多项式多点求值),求出导数,然后用多点求值的方法求出所有
P
′
(
X
[
i
]
)
P'(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(x−X[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(x−X[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'(X[i])} \frac {P(x)} {x-X[i]}
A0(x)=i=1∑n/2P′(X[i])Y[i]x−X[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'(X[i])} \frac {P(x)} {x-X[i]}
A1(x)=i=n/2+1∑nP′(X[i])Y[i]x−X[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'(x)}
xi+1=xi−g′(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 x⌈2n⌉),且
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'(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'(F_t(x))} {1!}(F_{t+1}(x)-F_t(x))+\frac {G''(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''(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'(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'(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×B≡1 (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×B−1≡0 (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)(1−lnBt(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;
}