咕了很久的多项式库,用的时候可以直接Ctrl+C加Ctrl+v了
洛谷模板
不说了,直接NTT背代码即可
int N,bit;
int rev[inf];
void FFT(ll a[],int f){
for (int i=0;i<N;i++){
if (rev[i]>i){
swap(a[i],a[rev[i]]);
}
}
for (int i=1;i<N;i*=2){
ll wn=Qpow(f==1?G:invG,(mod-1)/i/2);
for (int j=0;j<N;j+=i*2){
ll w=1;
for (int k=0;k<i;k++){
ll x=a[j+k],y=a[i+j+k]*w%mod;
a[j+k]=(x+y)%mod;
a[i+j+k]=(x-y+mod)%mod;
w=w*wn%mod;
}
}
}
if (f==-1){
ll invn=getinv(N);
for (int i=0;i<N;i++){
a[i]=a[i]*invn%mod;
}
}
return;
}
void Poly_mul(ll A[],ll B[],int n){
N=1;
while (N<=n){
N*=2;
bit++;
}
for (int i=0;i<N;i++){
rev[i]=(rev[i/2]/2)|((i&1)<<(bit-1));
}
FFT(A,1);
FFT(B,1);
for (int i=0;i<=N;i++){
A[i]=A[i]*B[i]%mod;
}
FFT(A,-1);
return;
}
洛谷模板
用三个模数计算后crt即可
代码过长,见这里
洛谷模板
即给多项式 A ( x ) A(x) A(x),求 B ( x ) B(x) B(x)使 A ( x ) × B ( x ) ≡ 1 ( m o d x n ) A(x)\times B(x)\equiv 1\pmod{x^n} A(x)×B(x)≡1(modxn)
考虑倍增,若求得 A ( x ) × B ′ ( x ) ≡ 1 ( m o d x ⌈ n 2 ⌉ ) A(x)\times B'(x)\equiv 1\pmod{x^{\lceil \frac{n}{2} \rceil}} A(x)×B′(x)≡1(modx⌈2n⌉),并已知 A ( x ) × B ( x ) ≡ 1 ( m o d x ⌈ n 2 ⌉ ) A(x)\times B(x)\equiv 1\pmod{x^{\lceil \frac{n}{2} \rceil}} A(x)×B(x)≡1(modx⌈2n⌉)
∴ A ( x ) ∗ ( B ′ ( x ) − B ( x ) ) ≡ 0 ( m o d x ⌈ n 2 ⌉ ) \therefore A(x)*(B'(x)-B(x))\equiv 0\pmod{x^{\lceil \frac{n}{2} \rceil}} ∴A(x)∗(B′(x)−B(x))≡0(modx⌈2n⌉)
∴ ( B ′ ( x ) − B ( x ) ) ≡ 0 ( m o d x ⌈ n 2 ⌉ ) \therefore (B'(x)-B(x))\equiv 0\pmod{x^{\lceil \frac{n}{2} \rceil}} ∴(B′(x)−B(x))≡0(modx⌈2n⌉)
∴ ( B ′ ( x ) − B ( x ) ) 2 = B ′ 2 ( x ) + B 2 ( x ) − 2 B ( x ) B ′ ( x ) ≡ 0 ( m o d x n ) \therefore (B'(x)-B(x))^2=B'^2(x)+B^2(x)-2B(x)B'(x)\equiv 0\pmod{x^n} ∴(B′(x)−B(x))2=B′2(x)+B2(x)−2B(x)B′(x)≡0(modxn)
∴ A ( x ) × ( B ′ 2 ( x ) + B 2 ( x ) − 2 B ( x ) B ′ ( x ) ) = A ( x ) B ′ 2 ( x ) + B ( x ) − 2 B ′ ( x ) ≡ 0 ( m o d x n ) \therefore A(x)\times (B'^2(x)+B^2(x)-2B(x)B'(x))=A(x)B'^2(x)+B(x)-2B'(x)\equiv 0\pmod{x^n} ∴A(x)×(B′2(x)+B2(x)−2B(x)B′(x))=A(x)B′2(x)+B(x)−2B′(x)≡0(modxn)
∴ B ( x ) ≡ B ′ ( x ) × ( 2 − A ( x ) B ′ ( x ) ) ( m o d x n ) \therefore B(x)\equiv B'(x)\times (2-A(x)B'(x))\pmod{x^n} ∴B(x)≡B′(x)×(2−A(x)B′(x))(modxn)
边界: B 0 = i n v ( A 0 ) B_0=inv(A_0) B0=inv(A0)
代码:
void Poly_cal(ll A[],ll B[],int n){
N=1,bit=0;
while (N<n*2){
N*=2;
bit++;
}
for (int i=0;i<N;i++){
rev[i]=(rev[i/2]/2)|((i&1)<<(bit-1));
}
FFT(A,1);
FFT(B,1);
for (int i=0;i<=N;i++){
B[i]=B[i]*(2-A[i]*B[i]%mod+mod)%mod;
}
FFT(B,-1);
for (int i=n;i<=N;i++){
B[i]=0;
}
return;
}
ll tmp[inf];
void Poly_inv(ll A[],ll ans[],int n){
if (n==1){
ans[0]=getinv(A[0]);
return;
}
Poly_inv(A,ans,(n+1)/2);
memset(tmp,0,sizeof(tmp));
for (int i=0;i<n;i++){
tmp[i]=A[i];
}
Poly_cal(tmp,ans,n);
return;
}
洛谷模板
即给多项式 A ( x ) A(x) A(x),求 B ( x ) B(x) B(x)使 B 2 ( x ) ≡ A ( x ) ( m o d x n ) B^2(x)\equiv A(x) \pmod{x^n} B2(x)≡A(x)(modxn)
考虑倍增,若求得 B ′ 2 ( x ) ≡ A ( x ) ( m o d x ⌈ n 2 ⌉ ) B'^2(x)\equiv A(x)\pmod{x^{\lceil \frac{n}{2} \rceil}} B′2(x)≡A(x)(modx⌈2n⌉),并已知 B 2 ( x ) ≡ A ( x ) ( m o d x ⌈ n 2 ⌉ ) B^2(x)\equiv A(x)\pmod{x^{\lceil \frac{n}{2} \rceil}} B2(x)≡A(x)(modx⌈2n⌉)
∴ B 2 ( x ) − B ′ 2 ( x ) ≡ 0 ( m o d x ⌈ n 2 ⌉ ) \therefore B^2(x)-B'^2(x)\equiv 0\pmod{x^{\lceil \frac{n}{2} \rceil}} ∴B2(x)−B′2(x)≡0(modx⌈2n⌉)
∴ B 4 ( x ) + B ′ 4 ( x ) − 2 B 2 ( x ) B ′ 2 ( x ) ≡ 0 ( m o d x n ) \therefore B^4(x)+B'^4(x)-2B^2(x)B'^2(x)\equiv 0\pmod{x^n} ∴B4(x)+B′4(x)−2B2(x)B′2(x)≡0(modxn)
∴ B 4 ( x ) + B ′ 4 ( x ) + 2 B 2 ( x ) B ′ 2 ( x ) ≡ 4 B 2 ( x ) B ′ 2 ( x ) ( m o d x n ) \therefore B^4(x)+B'^4(x)+2B^2(x)B'^2(x)\equiv 4B^2(x)B'^2(x)\pmod{x^n} ∴B4(x)+B′4(x)+2B2(x)B′2(x)≡4B2(x)B′2(x)(modxn)
∴ B 2 ( x ) + B ′ 2 ( x ) ≡ 2 B ( x ) B ′ ( x ) ( m o d x n ) \therefore B^2(x)+B'^2(x)\equiv 2B(x)B'(x)\pmod{x^n} ∴B2(x)+B′2(x)≡2B(x)B′(x)(modxn)
∴ A ( x ) + B ′ 2 ( x ) ≡ 2 B ( x ) B ′ ( x ) ( m o d x n ) \therefore A(x)+B'^2(x)\equiv 2B(x)B'(x)\pmod{x^n} ∴A(x)+B′2(x)≡2B(x)B′(x)(modxn)
∴ B ( x ) ≡ A ( x ) + B ′ 2 ( x ) 2 B ′ ( x ) ( m o d x n ) \therefore B(x)\equiv \frac{A(x)+B'^2(x)}{2B'(x)}\pmod{x^n} ∴B(x)≡2B′(x)A(x)+B′2(x)(modxn)
再用多项式求逆即可。
边界: B 0 = A 0 B_0=\sqrt{A_0} B0=A0(二次剩余)
代码(模板中 A 0 = 1 A_0=1 A0=1):
ll C[inf],B[inf],D[inf];
void Poly_sqrt(ll A[],ll ans[],int n){
if (n==1){
ans[0]=1;
return;
}
memset(B,0,sizeof(B));
memset(C,0,sizeof(C));
memset(D,0,sizeof(D));
Poly_sqrt(A,ans,(n+1)/2);
for (int i=0;i<n;i++){
C[i]=ans[i]*2%mod;
D[i]=ans[i];
B[i]=0;
}
Poly_inv(C,B,n);
Poly_mul(ans,D,n);
for (int i=0;i<n;i++){
ans[i]=(ans[i]+A[i])%mod;
}
Poly_mul(ans,B,n);
return;
}
见这里
代码:
void Poly_der(ll A[],ll ans[],int n){
for (int i=1;i<n;i++){
ans[i-1]=A[i]*i%mod;
}
ans[n-1]=0;
return;
}
void Poly_int(ll A[],ll ans[],int n){
for (int i=1;i<n;i++){
ans[i]=A[i-1]*getinv(i)%mod;
}
ans[0]=0;
return;
}
即给函数 A ( x ) A(x) A(x),求多项式 B ( x ) B(x) B(x)使 A ( B ( x ) ) ≡ 0 ( m o d x n ) A(B(x))\equiv 0 \pmod{x^n} A(B(x))≡0(modxn)
考虑倍增,若求得 A ( B ′ ( x ) ) ≡ 0 ( m o d x ⌈ n 2 ⌉ ) A(B'(x))\equiv 0\pmod{x^{\lceil \frac{n}{2} \rceil}} A(B′(x))≡0(modx⌈2n⌉)
(记 A ( n ) A^{(n)} A(n)为多项式 A ( x ) A(x) A(x)的 n n n阶倒数)
泰勒展开: A ( B ( x ) ) = ∑ i = 0 ∞ ( B ( x ) − B ′ ( x ) ) i × A ( n ) ( B ′ ( x ) ) i ! A(B(x))=\sum_{i=0}^{\infty}\frac{(B(x)-B'(x))^i\times A^{(n)}(B'(x))}{i!} A(B(x))=∑i=0∞i!(B(x)−B′(x))i×A(n)(B′(x))
因为 B ( x ) − B ′ ( x ) B(x)-B'(x) B(x)−B′(x)最低次数是 ⌈ n 2 ⌉ \lceil \frac{n}{2}\rceil ⌈2n⌉,当 i ≥ 2 i\geq 2 i≥2时在 ( m o d x n ) \pmod{x^n} (modxn)意义下为0
所以 A ( B ( x ) ) = A ( B ′ ( x ) ) + ( B ( x ) − B ′ ( x ) ) ∗ A ( 1 ) ( B ′ ( x ) ) ≡ 0 ( m o d x n ) A(B(x))=A(B'(x))+(B(x)-B'(x))*A^{(1)}(B'(x))\equiv 0 \pmod{x^n} A(B(x))=A(B′(x))+(B(x)−B′(x))∗A(1)(B′(x))≡0(modxn)
∴ B ( x ) ≡ B ′ ( x ) − A ( B ′ ( x ) ) A ( 1 ) ( B ′ ( x ) ) ( m o d x n ) \therefore B(x) \equiv B'(x)-\frac{A(B'(x))}{A^{(1)}(B'(x))} \pmod{x^n} ∴B(x)≡B′(x)−A(1)(B′(x))A(B′(x))(modxn)
代码(无)
洛谷模板
即给多项式 A ( x ) A(x) A(x),求 B ( x ) B(x) B(x)使 B ( x ) ≡ l n ( A ( x ) ) ( m o d x n ) B(x)\equiv ln(A(x)) \pmod{x^n} B(x)≡ln(A(x))(modxn)
(记函数 f ( x ) f(x) f(x)倒数为 f ′ ( x ) f'(x) f′(x))
两边求导得: B ′ ( x ) ≡ A ′ ( x ) A ( x ) ( m o d x n ) B'(x)\equiv \frac{A'(x)}{A(x)} \pmod{x^n} B′(x)≡A(x)A′(x)(modxn)(假装我知道 l n ( x ) ln(x) ln(x)的导数是 1 x \frac{1}{x} x1)
积回去即可(我也不知道为什么可以这样。。。) B ( x ) = ∫ A ′ ( x ) A ( x ) d x B(x)=\int \frac{A'(x)}{A(x)} dx B(x)=∫A(x)A′(x)dx
需要多项式求逆、求导、积分
代码:
void Poly_ln(ll A[],ll ans[],int n){
Poly_der(A,B,n);
Poly_inv(A,C,n);
Poly_mul(B,C,n);
Poly_int(B,ans,n);
return;
}
洛谷模板
即给多项式 A ( x ) A(x) A(x),求 B ( x ) B(x) B(x)使 B ( x ) ≡ e A ( x ) ( m o d x n ) B(x)\equiv e^{A(x)} \pmod{x^n} B(x)≡eA(x)(modxn)
两边取对数移项得: l n ( B ( x ) ) − A ( x ) ≡ 0 ( m o d x n ) ln(B(x))-A(x)\equiv 0\pmod{x^n} ln(B(x))−A(x)≡0(modxn)
设函数 F ( B ( x ) ) = l n ( B ( x ) ) − A ( x ) ≡ 0 ( m o d x n ) F(B(x))=ln(B(x))-A(x)\equiv 0\pmod{x^n} F(B(x))=ln(B(x))−A(x)≡0(modxn)
用牛顿迭代倍增即可
ll D[inf];
void Poly_exp(ll A[],ll ans[],int n){
if (n==1){
ans[0]=1;
return;
}
Poly_exp(A,ans,(n+1)/2);
memset(D,0,sizeof(D));
Poly_ln(ans,D,n);
for (int i=0;i<n;i++){
D[i]=((i==0?1:0)-D[i]+A[i]+mod)%mod;
}
Poly_mul(ans,D,n);
return;
}
即给出多项式 A ( x ) A(x) A(x)(长为n)和 B ( x ) B(x) B(x)(长为m),求 R ( x ) R(x) R(x)与 P ( x ) P(x) P(x)使 A ( x ) ≡ B ( x ) × P ( x ) + R ( x ) ( m o d x n ) A(x)\equiv B(x)\times P(x)+R(x)\pmod{x^n} A(x)≡B(x)×P(x)+R(x)(modxn),且 P ( x ) P(x) P(x)次数小于等于 n − m n-m n−m, P ( x ) P(x) P(x)次数小于等于 m − 1 m-1 m−1。
我们把一个多项式系数翻转,可表示为 x n A ( 1 x ) x^nA(\frac{1}{x}) xnA(x1)(因为 x n A ( 1 x ) = x n ∑ i = 0 n a i 1 x i = ∑ i = 0 n a n − i x i x^nA(\frac{1}{x})=x^n\sum_{i=0}^na_i\frac{1}{x^i}=\sum_{i=0}^na_{n-i}x^i xnA(x1)=xn∑i=0naixi1=∑i=0nan−ixi)
根据题意,可以证明 x n A ( 1 x ) ≡ x n ( B ( 1 x ) × P ( 1 x ) + R ( 1 x ) ) ( m o d x n ) x^nA(\frac{1}{x})\equiv x^n\left( B(\frac{1}{x})\times P(\frac{1}{x})+R(\frac{1}{x})\right) \pmod{x^n} xnA(x1)≡xn(B(x1)×P(x1)+R(x1))(modxn)成立
即 x n A ( 1 x ) ≡ x m B ( 1 x ) × x n − m P ( 1 x ) + x n − m + 1 × x m − 1 R ( 1 x ) ( m o d x n ) x^nA(\frac{1}{x})\equiv x^m B(\frac{1}{x})\times x^{n-m}P(\frac{1}{x})+x^{n-m+1}\times x^{m-1}R(\frac{1}{x}) \pmod{x^n} xnA(x1)≡xmB(x1)×xn−mP(x1)+xn−m+1×xm−1R(x1)(modxn)
因为 x n − m P ( 1 x ) x^{n-m}P(\frac{1}{x}) xn−mP(x1)最高次是 n − m n-m n−m, x n − m + 1 × x m − 1 R ( 1 x ) x^{n-m+1}\times x^{m-1}R(\frac{1}{x}) xn−m+1×xm−1R(x1)最低次项是 n − m + 1 n-m+1 n−m+1
所以 x n A ( 1 x ) ≡ x m B ( 1 x ) × x n − m P ( 1 x ) ( m o d x n − m + 1 ) x^nA(\frac{1}{x})\equiv x^m B(\frac{1}{x})\times x^{n-m}P(\frac{1}{x})\pmod{x^{n-m+1}} xnA(x1)≡xmB(x1)×xn−mP(x1)(modxn−m+1)
可用多项式求逆求出 x n − m P ( 1 x ) x^{n-m}P(\frac{1}{x}) xn−mP(x1),反过来就是 P ( x ) P(x) P(x),代回去求出 R ( x ) R(x) R(x)即可。
代码:
ll C[inf],D[inf],E[inf];
void Poly_div(ll A[],ll B[],ll P[],ll R[],int n,int m){
for (int i=0;i<n;i++){
C[i]=A[n-i-1];
}
for (int i=0;i<m;i++){
D[i]=B[m-i-1];
}
Poly_inv(D,E,n-m+2);
Poly_mul(E,C,n-m+2+n);
memset(D,0,sizeof(D));
for (int i=0;i<n-m+1;i++){
P[i]=E[n-m-i];
D[i]=P[i];
}
Poly_mul(D,B,n);
for (int i=0;i<m-1;i++){
R[i]=(A[i]-D[i]+mod)%mod;
}
return;
}
未完待续。。。