学习笔记:多项式半家桶
已经吃撑了
多项式求逆
对于多项式 \(A(x)\) ,求多项式 \(B(x)\), 满足 \(A(x) * B(x) \equiv 1 \pmod{x^n}\)。
递归求解。
求模 \(x^n\) 的逆元时,假设先求出了模 \(x^{\lceil\frac{n}{2}\rceil}\) 的逆元。
设模 \(x^n\) 逆元为 \(B\),模 \(x^{\lceil\frac{n}{2}\rceil}\) 逆元为 \(B'\),则:
且
所以
然后就可以从下往上递推了,注意边界
一个加速的技巧是把 \(B'\) 和 \(A'\) 转成点值表达式后直接算出 \(B'\) 的点值表达式,这样可以减少NTT的次数,显著提高效率(指7000ms-->1000ms)
求逆
void inverse(int *A,int *B,int n){
static int a[M],b[M];
b[0]=qpow(A[0],Mod-2,Mod);
int bas=2;
while(bas<=2*n){
for(int i=0;i<bas;i++) a[i]=A[i];
int len=init(bas+bas-2);
NTT(b,len,1);NTT(a,len,1);
for(int i=0;i<len;i++) b[i]=(1ll*b[i]*2%Mod-1ll*a[i]*b[i]%Mod*b[i]%Mod+Mod)%Mod;
NTT(b,len,-1);
for(int i=bas;i<len;i++) b[i]=0;
bas<<=1;
}
for(int i=0;i<bas;i++) B[i]=b[i];
for(int i=0;i<bas;i++) a[i]=b[i]=0;
}
多项式开根
对于一个 \(n-1\) 次多项式 \(F(x)\),求一个在 \({} \bmod x^n\) 意义下的多项式 \(G(x)\),使得 \(G^2(x) \equiv F(x) \pmod{x^n}\)。若有多解,请取零次项系数较小的作为答案。
设 \(H^2(x)\equiv F(x)(mod\ x^{\lceil\frac n2 \rceil})\)
有:
同样可以递推实现
开根
void Sqrt(int *A,int *B,int n){
static int a[M],b[M],revb[M];
b[0]=1;
int bas=2;
while(bas<=2*n){
for(int i=0;i<bas;i++) a[i]=A[i];
inverse(b,revb,bas-1);
Mul(revb,a,a,bas-1,bas-1);
for(int i=0;i<bas;i++) b[i]=1ll*add(a[i],b[i])*inv2%Mod;
bas<<=1;
}
for(int i=0;i<bas;i++) B[i]=b[i];
for(int i=0;i<bas;i++) a[i]=b[i]=revb[i]=0;
}
多项式求导
求多项式 \(F(x)\) 的导数 \(F'(x)\)
因为
所以
求导
void Dao(int *A,int *B,int n){
for(int i=1;i<=n;i++) B[i-1]=1ll*A[i]*i%Mod;
B[n]=0;
}
多项式求不定积分
求多项式 \(F(x)\) 的不定积分 \(G(x)\)
因为
所以
积分(暗藏玄只因)
void Zhiyin(int *A,int *B,int n){
for(int i=1;i<=n;i++) B[i]=1ll*A[i-1]*qpow(i,Mod-2,Mod)%Mod;
B[0]=0;
}
多项式求Ln
给出 \(n-1\) 次多项式 \(A(x)\),求一个 \(\bmod{\:x^n}\) 下的多项式 \(B(x)\),满足 \(B(x) \equiv \ln A(x)\).
为了这个学了导数
因为\(F'(x)=\frac{1}{x}\)
所以
所以对 \(A\) 求导再求逆再乘起来再积回去就行了
求Ln
void Ln(int *A,int *B,int n){
static int a[M],b[M];
Dao(A,a,n);
inverse(A,b,n);
Mul(a,b,a,n,n);
Zhiyin(a,B,n);
}
多项式求exp
给出 \(n-1\) 次多项式 \(A(x)\),求一个 \(\bmod{\:x^n}\) 下的多项式 \(B(x)\),满足 \(B(x) \equiv \text e^{A(x)}\)。
咕了,要用到泰勒展开和牛顿迭代,什么时候看懂了再补过程
求exp
void Exp(int *A,int *B,int n){
if(n==0) return B[0]=1,void();
static int f[M];
Exp(A,B,n>>1);
Ln(B,f,n);
f[0]=minu(A[0]+1,f[0]);
for(int i=1;i<=n;i++) f[i]=minu(A[i],f[i]);
Mul(f,B,B,n,n);
}