多项式7/n家桶
多项式求逆
\[\begin{aligned}
&F(x) * G(x) \equiv 1 \pmod{x^n} \\
&F(x) * G(x) \equiv 1 \pmod{x^{\lceil \frac{n}{2}\rceil}} \\
&我们设F(x)*H(x)\equiv 1 \pmod{x^{\lceil \frac{n}{2}\rceil}}\\
&F(x)*(G(x)-H(x)) \equiv 0 \pmod{x^{\lceil \frac{n}{2}\rceil}}\\
&(G(x)-H(x))\equiv 0 \pmod{x^{\lceil \frac{n}{2}\rceil}}\\
&(G(x)-H(x))^2\equiv 0 \pmod{x^n}\\
&G^2(x)+H^2(x)-2G(x)H(x)\equiv 0 \pmod{x^n}\\
&F(x)G^2(x)+F(x)H^2(x)-2F(x)G(x)H(x)\equiv 0 \pmod{x^n}\\
&G(x)+F(x)H^2(x)-2H(x)\equiv 0 \pmod{x^n}\\
& G(x)\equiv 2H(x)-F(x)H^2(x)\pmod{x^n}\\
&当n=1时,F(x)=[x^0]F(x)x,G(x)=([x^0]F(x)x)^{-1}
\end{aligned}
\]
很多题解都采用了上面的证法,然而我初次看时有很多不理解的地方。其中最令我感到迷惑的是为什么用向上取整而不能用向下取整。现在给出解释:
\[
\begin{aligned}
1. &a \equiv 1 \pmod {x^n} \Rightarrow a\equiv 1 \pmod {x^{\lceil \frac{n}{2}\rceil}}\\
证明:
&a \equiv 1 \pmod {x^n}\\
&x^n \mid a-1\\
&{x^{\lceil \frac{n}{2}\rceil}}{x^{\lfloor \frac{n}{2} \rfloor}} \mid a-1\\
&{x^{\lceil \frac{n}{2}\rceil}}\mid a-1\\
&a \equiv 1 \pmod {x^{\lceil \frac{n}{2}\rceil}}\\
&注意到,向下取整同样满足这个性质,然而这并不重要(主不在乎\\
2.&a\equiv 0 \pmod {x^{\lceil \frac{n}{2}\rceil}} \rightarrow a^2\equiv 0 \pmod{x^n}\\
证明:
&a^2 \equiv 0 \pmod {x^{2 {\lceil \frac{n}{2}\rceil}}}\\
& x^{{\lceil \frac{n}{2}\rceil}} \mid a^2\\
& x^n\mid x^{2 {\lceil \frac{n}{2}\rceil}} \\
&a^2 \equiv 0 \pmod {x^n}\\
&注意到,向下取整并不满足这个性质,因此只能采取向上取整的方式\\
\end{aligned}
\]
有了这样的性质,最上面的证明自然就具有了正确性。
然而似乎并没有什么卵用,因为求逆是自底而上倍增实现的,根本用不着什么向下取整。
展开查看源码
多项式除法
\[
\]
多项式开根
\[
\begin{aligned}
&G(x)^2 \equiv F(x) \pmod{x^n}\\
设&H(x)^2 \equiv F(x) \pmod {x^{\lceil \frac{n}{2} \rceil}}\\
&G(x)^2 \equiv F(x) \pmod {x^{\lceil \frac{n}{2} \rceil}}\\
&G(x)^2 \equiv H(x)^2 \pmod {x^{\lceil \frac{n}{2} \rceil}}\\
&G(x) \equiv H(x)\pmod {x^{\lceil \frac{n}{2} \rceil}}\\
&(G(x) -H(x))^2\equiv 0 \pmod {x^{n}}\\
&G(x)^2+H(x)^2-2G(x)H(x)\equiv 0 \pmod {x^{n}}\\
&F(x)+H(x)^2-2G(x)H(x)\equiv 0 \pmod {x^{n}}\\
& G(x)\equiv \frac{F(x)+H(x)^2}{2H(x)} \pmod {x^{n}}\\
\end{aligned}
\]
套个多项式求逆倍增即可
展开查看源码
void poly_sqrt(int a[],int b[],int len)
{
int tmp[maxn]={},H[maxn]={},tmp2[maxn]={};
b[0]=1;
int ln=1;
while(ln<(len<<1))
{
for(int i=0;i<ln;i++)tmp[i]=a[i];
for(int i=0;i<ln;i++)tmp2[i]=2ll*b[i]%P;
poly_inv(tmp2,H,ln);
init(ln);
NTT(b,1),NTT(tmp,1),NTT(H,1);
for(int i=0;i<lim;i++)b[i]=1ll*H[i]%P*(tmp[i]+1ll*b[i]*b[i]%P)%P;
NTT(b,-1);
for(int i=ln;i<lim;i++)b[i]=0;
for(int i=0;i<lim;i++)H[i]=tmp[i]=0;
ln<<=1;
}
}
多项式对数
\[G(x) \equiv \ln(F(x)) \pmod{x^n}\\
G(x)' \equiv \ln'(F(x))F'(x) \pmod{x^n}\\
G(x)' \equiv \frac{F'(x)}{F(x)} \pmod{x^n}\\
\]
G的导数等于F的导数乘上F的乘法逆,对G的导数做个积分即可得出G
多项式EXP
咕咕咕
多项式快速幂
全家桶
#include<bits/stdc++.h>
using namespace std;
const int P = 998244353,gi=332748118;
const int maxn =5e5;
int w[2][maxn],r[maxn],lim;
int fsp(int a,int b=P-2)
{
int s=1;
while(b)
{
if(b&1)s=1ll*s*a%P;
b>>=1;
a=1ll*a*a%P;
}
return s;
}
void init(int len)
{
lim=1;
int l=0;
while(lim<len)lim<<=1,l++;
int wn=fsp(3,(P-1)/lim),cw=fsp(gi,(P-1)/lim);
w[0][0]=w[1][0]=1;
for(int i=1;i<lim;i++)
{
w[0][i]=1ll*w[0][i-1]*cw%P;
w[1][i]=1ll*w[1][i-1]*wn%P;
r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
}
}
void NTT(int num[],int typ)
{
for(int i=0;i<lim;i++)if(i<r[i])swap(num[i],num[r[i]]);
for(int mid=1,t=(lim>>1);mid<lim;mid<<=1,t>>=1)
{
for(int i=0;i<lim;i+=mid<<1)
{
for(int j=0;j<mid;j++)
{
int x=num[i+j],y=1ll*num[i+j+mid]*w[typ][t*j]%P;
num[i+j]=(x+y)%P;
num[i+j+mid]=(x-y+P)%P;
}
}
}
if(typ==0)
{
int inv=fsp(lim);
for(int i=0;i<lim;i++)num[i]=1ll*num[i]*inv%P;
}
}
void copy(int a[],int b[],int len)
{
for(int i=0;i<len;i++)b[i]=a[i];
}
void poly_mul(int f[],int g[],int ans[],int n,int m)
{
int a[maxn]={},b[maxn]={};
copy(f,a,n),copy(g,b,m);
init(n+m-1);
NTT(a,1),NTT(b,1);
for(int i=0;i<lim;i++)
{
a[i]=1ll*a[i]*b[i]%P;
}
NTT(a,0);
copy(a,ans,n+m-1);
}
void poly_inv(int f[],int ans[],int n)
{
int a[maxn]={},b[maxn]={};
b[0]=fsp(f[0]);
int len=2;
while(len<(n<<1))//2
{
copy(f,a,len);
init(len<<1);//
NTT(a,1),NTT(b,1);
for(int i=0;i<lim;i++)
{
b[i]=(2ll*b[i]%P-1ll*b[i]*b[i]%P*a[i]%P+P)%P;
}
NTT(b,0);
for(int i=len;i<lim;i++)b[i]=0;
len<<=1;
}
copy(b,ans,n);
}
void poly_sqrt(int f[],int ans[],int n)
{
int a[maxn]={},b[maxn]={},c[maxn]={};
b[0]=1;
int len=2;
while(len<(n<<1))
{
copy(f,a,len);
for(int i=0;i<len;i++)c[i]=2ll*b[i]%P;
poly_inv(c,c,len);
init(len<<1);
NTT(a,1),NTT(b,1),NTT(c,1);
for(int i=0;i<lim;i++)
{
b[i]=c[i]%P*(a[i]+1ll*b[i]*b[i]%P)%P;
}
NTT(b,0);
for(int i=len;i<lim;i++)b[i]=c[i]=a[i]=0;
len<<=1;
}
copy(b,ans,n);
}
void Poly_div(int f[],int g[],int Q[],int R[],int n,int m)
{
int a[maxn]={},b[maxn]={};
copy(f,a,n),copy(g,b,m);
reverse(a,a+n);
reverse(b,b+m);
for(int i=n-m+2;i<m;i++)b[i]=0;
poly_inv(b,b,n-m+1);
poly_mul(a,b,Q,n-m+1,n-m+1);
reverse(Q,Q+n-m+1);
for(int i=n-m+1;i<n;i++)Q[i]=0;
poly_mul(Q,g,R,n-m+1,m);
for(int i=0;i<m-1;i++)
{
R[i]=(f[i]-R[i]+P)%P;
}
}
void poly_deri(int f[],int ans[],int n)
{
int a[maxn]={};
copy(f,a,n);
for(int i=0;i<n-1;i++)
{
ans[i]=1ll*(i+1)*a[i+1]%P;
}
ans[n-1]=0;
}
void poly_intg(int f[],int ans[],int n)
{
int a[maxn]={};
copy(f,a,n);
for(int i=1;i<=n;i++)
{
ans[i]=1ll*a[i-1]*fsp(i)%P;
}
ans[0]=0;
}
void Poly_Lyin(int f[],int ans[],int n)
{
int a[maxn]={},b[maxn]={};
poly_inv(f,a,n);
poly_deri(f,b,n);
poly_mul(a,b,a,n,n-1);
poly_intg(a,a,n);
copy(a,ans,n);
}
void Poly_exp(int f[],int ans[],int n)
{
int a[maxn]={},b[maxn]={},c[maxn]={};
b[0]=1;
int len=2;
while(len<(n<<1))
{
copy(f,a,len);
Poly_Lyin(b,c,len);
init(len<<1);
c[0]=(a[0]+1-c[0]+P)%P;
for(int i=1;i<lim;i++)
{
c[i]=(a[i]-c[i]+P)%P;
}
NTT(c,1),NTT(b,1);
for(int i=0;i<lim;i++)
{
b[i]=1ll*b[i]*c[i]%P;
}
NTT(b,0);
for(int i=len;i<lim;i++)b[i]=c[i]=a[i]=0;
for(int i=0;i<len;i++)c[i]=a[i]=0;
len<<=1;
}
copy(b,ans,n);
}
void Poly_fsp(int f[],int ans[],int k,int k1,int n)
{
int g[maxn]={};
int t=n;
for(int i=0;i<n;i++)
{
if(f[i]!=0)
{
t=i;
break;
}
}
for(int i=t;i<n;i++)
{
g[i-t]=f[i];
}
if(1ll*t*k>n)return;
int A=fsp(g[0],k1),I=fsp(g[0]);
for(int i=0;i<n;i++)
{
g[i]=1ll*g[i]*I%P;
}
Poly_Lyin(g,g,n-t);
for(int i=0;i<n-t;i++)g[i]=1ll*g[i]*k%P;
Poly_exp(g,g,n-t);
for(int i=0;i<n-t;i++)
{
g[i]=1ll*g[i]*A%P;
if(i+1ll*k*t<n)ans[i+k*t]=g[i];
}
}