多项式乘法
FFT
#include <bits/stdc++.h>
using namespace std;
const int N=1e7+6;
const double P=acos(-1);
int n,m;
struct node{
double x,y;
node(double xx=0,double yy=0){
x=xx;
y=yy;
}
}a[N],b[N];
node operator + (node x,node y){return node(x.x+y.x,x.y+y.y);}
node operator - (node x,node y){return node(x.x-y.x,x.y-y.y);}
node operator * (node x,node y){return node(x.x*y.x-x.y*y.y,x.x*y.y+x.y*y.x);}
void fft(int lim,node *a,int t){
if(lim==1) return;
node a1[lim],a2[lim];
for(int i=0;i<=lim;i++){
if(i%2) a2[i/2]=a[i];
else a1[i/2]=a[i];
}
fft(lim/2,a1,t);
fft(lim/2,a2,t);
node wn=node(cos(2.*P/lim),t*sin(2.*P/lim));
node w=node(1,0);
for(int i=0;i<(lim/2);i++,w=w*wn){
a[i]=a1[i]+w*a2[i];
a[i+lim/2]=a1[i]-w*a2[i];
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<=n;i++) scanf("%lf",&a[i].x);
for(int i=0;i<=m;i++) scanf("%lf",&b[i].x);
int lim=1;
while(lim<=n+m) lim*=2;
fft(lim,a,1);
fft(lim,b,1);
for(int i=0;i<=lim;i++) a[i]=a[i]*b[i];
fft(lim,a,-1);
for(int i=0;i<=n+m;i++) printf("%d ",(int)(a[i].x/lim+0.5));
return 0;
}
NTT
#include <bits/stdc++.h>
using namespace std;
const int N=1e7+6;
const int MOD=998244353;
const int G=3;
const int GI=332748118;
int n,m,lim;
int a[N],b[N],r[N];
int fp(int a,int r){
int res=1;
for(;r;r>>=1){
if(r&1) res=(1ll*res*a)%MOD;
a=(1ll*a*a)%MOD;
}
return res;
}
void ntt(int *a,int t){
for(int i=0;i<lim;i++) if(i<r[i]) swap(a[i],a[r[i]]);
for(int i=1;i<lim;i<<=1){
int wn=fp(t==1?G:GI,(MOD-1)/(i<<1));
for(int j=0;j<lim;j+=(i<<1)){
int w=1;
for(int k=0;k<i;k++,w=(1ll*w*wn)%MOD){
int x=a[j+k];
int y=(1ll*w*a[j+k+i])%MOD;
a[j+k]=(1ll*x+y)%MOD;
a[j+k+i]=(1ll*x-y+MOD)%MOD;
}
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<=n;i++) scanf("%d",&a[i]);
for(int i=0;i<=m;i++) scanf("%d",&b[i]);
lim=1;
int l=0;
while(lim<=n+m) lim*=2,l++;
for(int i=0;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
ntt(a,1);
ntt(b,1);
for(int i=0;i<lim;i++) a[i]=(1ll*a[i]*b[i])%MOD;
ntt(a,-1);
int inv=fp(lim, MOD-2);
for(int i=0;i<=n+m;i++) printf("%d ",(1ll*a[i]*inv)%MOD);
return 0;
}
多项式乘法逆
#include <bits/stdc++.h>
using namespace std;
const int N=1e7+6;
const int MOD=998244353;
const int G=3;
const int GI=332748118;
int n,m;
int a[N],b[N],c[N],r[N],g[N];
int fp(int a,int r){
int res=1;
for(;r;r>>=1){
if(r&1) res=(1ll*res*a)%MOD;
a=(1ll*a*a)%MOD;
}
return res;
}
void ntt(int *a,int lim,int t){
for(int i=0;i<lim;i++) if(i<r[i]) swap(a[i],a[r[i]]);
for(int i=1;i<lim;i<<=1){
int wn=fp(t==1?G:GI,(MOD-1)/(i<<1));
for(int j=0;j<lim;j+=(i<<1)){
int w=1;
for(int k=0;k<i;k++,w=(1ll*w*wn)%MOD){
int x=a[j+k];
int y=(1ll*w*a[j+k+i])%MOD;
a[j+k]=(1ll*x+y)%MOD;
a[j+k+i]=(1ll*x-y+MOD)%MOD;
}
}
}
}
void invs(int d,int* a,int* b){
if(d==1){
b[0]=fp(a[0],MOD-2);
return;
}
invs((d+1)>>1,a,b);
int lim=1,l=0;
while(lim<(d<<1)) lim<<=1,l++;
for(int i=1;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
for(int i=0;i<lim;i++) c[i]=a[i];
for(int i=d;i<lim;i++) c[i]=0;
ntt(c,lim,1);
ntt(b,lim,1);
for(int i=0;i<lim;i++) b[i]=(2-1ll*c[i]*b[i]%MOD+MOD)%MOD*b[i]%MOD;
ntt(b,lim,-1);
int inv=fp(lim, MOD-2);
for(int i=0;i<lim;i++) b[i]=(1ll*inv*b[i])%MOD;
for(int i=d;i<lim;i++) b[i]=0;
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
invs(n,a,b);
for(int i=0;i<n;i++) printf("%d ",b[i]);
return 0;
}
多项式开根
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+6;
const int MOD=998244353;
const int INV=499122177;
const int G=3;
const int GI=332748118;
int n,m;
int a[N],b[N],c[N],p[N],q[N],r[N],g[N];
int fp(int a,int r){
int res=1;
for(;r;r>>=1){
if(r&1) res=(1ll*res*a)%MOD;
a=(1ll*a*a)%MOD;
}
return res;
}
void ntt(int *a,int lim,int t){
for(int i=0;i<lim;i++) if(i<r[i]) swap(a[i],a[r[i]]);
for(int i=1;i<lim;i<<=1){
int wn=fp(t==1?G:GI,(MOD-1)/(i<<1));
for(int j=0;j<lim;j+=(i<<1)){
int w=1;
for(int k=0;k<i;k++,w=(1ll*w*wn)%MOD){
int x=a[j+k];
int y=(1ll*w*a[j+k+i])%MOD;
a[j+k]=(1ll*x+y)%MOD;
a[j+k+i]=(1ll*x-y+MOD)%MOD;
}
}
}
}
void invs(int d,int* a,int* b){
if(d==1){
b[0]=fp(a[0],MOD-2);
return;
}
invs((d+1)>>1,a,b);
int lim=1,l=0;
while(lim<(d<<1)) lim<<=1,l++;
for(int i=1;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
for(int i=0;i<lim;i++) c[i]=a[i];
for(int i=d;i<lim;i++) c[i]=0;
ntt(c,lim,1);
ntt(b,lim,1);
for(int i=0;i<lim;i++) b[i]=(2-1ll*c[i]*b[i]%MOD+MOD)%MOD*b[i]%MOD;
ntt(b,lim,-1);
int inv=fp(lim, MOD-2);
for(int i=0;i<lim;i++) b[i]=(1ll*inv*b[i])%MOD;
for(int i=d;i<lim;i++) b[i]=0;
}
void sqrts(int *a,int *b,int d){
if(d==1){
b[0]=1;
return;
}
sqrts(a,b,(d+1)>>1);
int lim=1,l=0;
while(lim<(d<<1)) lim<<=1,l++;
for(int i=0;i<lim;i++) p[i]=0;
for(int i=0;i<lim;i++) q[i]=a[i];
for(int i=d;i<lim;i++) q[i]=0;
invs(lim>>1,b,p);
for(int i=1;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
ntt(q,lim,1);
ntt(p,lim,1);
for(int i=0;i<lim;i++) q[i]=(1ll*q[i]*p[i])%MOD;
ntt(q,lim,-1);
int inv=fp(lim, MOD-2);
for(int i=0;i<lim;i++) q[i]=(1ll*inv*q[i])%MOD;
for(int i=0;i<lim;i++) b[i]=(1ll*b[i]+q[i])%MOD*INV%MOD;
for(int i=d;i<lim;i++) b[i]=0;
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
sqrts(a,g,n);
for(int i=0;i<n;i++) printf("%d ",g[i]);
return 0;
}
多项式除法
#include <bits/stdc++.h>
using namespace std;
const int N=1e7+6;
const int MOD=998244353;
const int G=3;
const int GI=332748118;
int n,m;
int a[N],b[N],c[N],r[N],f[N],g[N],p[N],q[N],s[N],v[N];
int fp(int a,int r){
int res=1;
for(;r;r>>=1){
if(r&1) res=(1ll*res*a)%MOD;
a=(1ll*a*a)%MOD;
}
return res;
}
void ntt(int *a,int lim,int t){
for(int i=0;i<lim;i++) if(i<r[i]) swap(a[i],a[r[i]]);
for(int i=1;i<lim;i<<=1){
int wn=fp(t==1?G:GI,(MOD-1)/(i<<1));
for(int j=0;j<lim;j+=(i<<1)){
int w=1;
for(int k=0;k<i;k++,w=(1ll*w*wn)%MOD){
int x=a[j+k];
int y=(1ll*w*a[j+k+i])%MOD;
a[j+k]=(1ll*x+y)%MOD;
a[j+k+i]=(1ll*x-y+MOD)%MOD;
}
}
}
}
void invs(int d,int* a,int* b){
if(d==1){
b[0]=fp(a[0],MOD-2);
return;
}
invs((d+1)>>1,a,b);
int lim=1,l=0;
while(lim<(d<<1)) lim<<=1,l++;
for(int i=1;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
for(int i=0;i<lim;i++) c[i]=a[i];
for(int i=d;i<lim;i++) c[i]=0;
ntt(c,lim,1);
ntt(b,lim,1);
for(int i=0;i<lim;i++) b[i]=(2-1ll*c[i]*b[i]%MOD+MOD)%MOD*b[i]%MOD;
ntt(b,lim,-1);
int inv=fp(lim, MOD-2);
for(int i=0;i<lim;i++) b[i]=(1ll*inv*b[i])%MOD;
for(int i=d;i<lim;i++) b[i]=0;
}
void divs(int *a,int *b,int n,int m){
for(int i=0;i<=n;i++) f[n-i]=a[i];
for(int i=0;i<=m;i++) g[m-i]=b[i];
for(int i=n-m+1;i<=m;i++) g[i]=0;
invs(n-m+1,g,v);
int lim=1,l=0;
while(lim<((2*n-m-1)<<1)) lim*=2,l++;
for(int i=0;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
ntt(f,lim,1);
ntt(v,lim,1);
for(int i=0;i<lim;i++) f[i]=(1ll*f[i]*v[i])%MOD;
ntt(f,lim,-1);
int inv=fp(lim, MOD-2);
for(int i=0;i<lim;i++) f[i]=(1ll*inv*f[i])%MOD;
for(int i=0;i<n-m+1;i++) p[i]=f[n-m-i];
lim=1,l=0;
while(lim<((2*n-m-1)<<1)) lim*=2,l++;
for(int i=0;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
for(int i=0;i<lim;i++) s[i]=p[i];
ntt(b,lim,1);
ntt(s,lim,1);
for(int i=0;i<lim;i++) b[i]=(1ll*b[i]*s[i])%MOD;
ntt(b,lim,-1);
inv=fp(lim, MOD-2);
for(int i=0;i<lim;i++) b[i]=(1ll*inv*b[i])%MOD;
for(int i=0;i<m;i++) q[i]=(a[i]-b[i]+MOD)%MOD;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<=n;i++) scanf("%d",&a[i]);
for(int i=0;i<=m;i++) scanf("%d",&b[i]);
divs(a,b,n,m);
for(int i=0;i<=n-m;i++) printf("%d ",p[i]);
printf("\n");
for(int i=0;i<m;i++) printf("%d ",q[i]);
return 0;
}
多项式对数函数
#include <bits/stdc++.h>
using namespace std;
const int N=1e7+6;
const int MOD=998244353;
const int G=3;
const int GI=332748118;
int n,m;
int a[N],b[N],c[N],r[N],g[N],p[N],q[N];
int fp(int a,int r){
int res=1;
for(;r;r>>=1){
if(r&1) res=(1ll*res*a)%MOD;
a=(1ll*a*a)%MOD;
}
return res;
}
void ntt(int *a,int lim,int t){
for(int i=0;i<lim;i++) if(i<r[i]) swap(a[i],a[r[i]]);
for(int i=1;i<lim;i<<=1){
int wn=fp(t==1?G:GI,(MOD-1)/(i<<1));
for(int j=0;j<lim;j+=(i<<1)){
int w=1;
for(int k=0;k<i;k++,w=(1ll*w*wn)%MOD){
int x=a[j+k];
int y=(1ll*w*a[j+k+i])%MOD;
a[j+k]=(1ll*x+y)%MOD;
a[j+k+i]=(1ll*x-y+MOD)%MOD;
}
}
}
}
void invs(int d,int* a,int* b){
if(d==1){
b[0]=fp(a[0],MOD-2);
return;
}
invs((d+1)>>1,a,b);
int lim=1,l=0;
while(lim<(d<<1)) lim<<=1,l++;
for(int i=1;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
for(int i=0;i<lim;i++) c[i]=a[i];
for(int i=d;i<lim;i++) c[i]=0;
ntt(c,lim,1);
ntt(b,lim,1);
for(int i=0;i<lim;i++) b[i]=(2-1ll*c[i]*b[i]%MOD+MOD)%MOD*b[i]%MOD;
ntt(b,lim,-1);
int inv=fp(lim, MOD-2);
for(int i=0;i<lim;i++) b[i]=(1ll*inv*b[i])%MOD;
for(int i=d;i<lim;i++) b[i]=0;
}
void lns(int *a,int *b,int d){
for(int i=1;i<d;i++) p[i-1]=(1ll*i*a[i])%MOD;p[d-1]=0;
invs(d,a,q);
int lim=1,l=0;
while(lim<(d<<1)) lim<<=1,l++;
for(int i=1;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
ntt(p,lim,1);
ntt(q,lim,1);
for(int i=0;i<lim;i++) p[i]=(1ll*p[i]*q[i])%MOD;
ntt(p,lim,-1);
int inv=fp(lim, MOD-2);
for(int i=0;i<lim;i++) p[i]=(1ll*inv*p[i])%MOD;
for(int i=1;i<d;i++) b[i]=(1ll*p[i-1]*fp(i,MOD-2))%MOD;b[0]=0;
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
lns(a,b,n);
for(int i=0;i<n;i++) printf("%d ",b[i]);
return 0;
}
多项式指数函数
#include <bits/stdc++.h>
using namespace std;
const int N=1e7+6;
const int MOD=998244353;
const int G=3;
const int GI=332748118;
int n,m;
int a[N],b[N],c[N],r[N],g[N],p[N],q[N],u[N],v[N];
int fp(int a,int r){
int res=1;
for(;r;r>>=1){
if(r&1) res=(1ll*res*a)%MOD;
a=(1ll*a*a)%MOD;
}
return res;
}
void ntt(int *a,int lim,int t){
for(int i=0;i<lim;i++) if(i<r[i]) swap(a[i],a[r[i]]);
for(int i=1;i<lim;i<<=1){
int wn=fp(t==1?G:GI,(MOD-1)/(i<<1));
for(int j=0;j<lim;j+=(i<<1)){
int w=1;
for(int k=0;k<i;k++,w=(1ll*w*wn)%MOD){
int x=a[j+k];
int y=(1ll*w*a[j+k+i])%MOD;
a[j+k]=(1ll*x+y)%MOD;
a[j+k+i]=(1ll*x-y+MOD)%MOD;
}
}
}
}
void invs(int d,int* a,int* b){
if(d==1){
b[0]=fp(a[0],MOD-2);
return;
}
invs((d+1)>>1,a,b);
int lim=1,l=0;
while(lim<(d<<1)) lim<<=1,l++;
for(int i=1;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
for(int i=0;i<lim;i++) c[i]=a[i];
for(int i=d;i<lim;i++) c[i]=0;
ntt(c,lim,1);
ntt(b,lim,1);
for(int i=0;i<lim;i++) b[i]=(2-1ll*c[i]*b[i]%MOD+MOD)%MOD*b[i]%MOD;
ntt(b,lim,-1);
int inv=fp(lim, MOD-2);
for(int i=0;i<lim;i++) b[i]=(1ll*inv*b[i])%MOD;
for(int i=d;i<lim;i++) b[i]=0;
}
void lns(int *a,int *b,int d){
for(int i=1;i<d;i++) p[i-1]=(1ll*i*a[i])%MOD;p[d-1]=0;
invs(d,a,q);
int lim=1,l=0;
while(lim<(d<<1)) lim<<=1,l++;
for(int i=1;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
ntt(p,lim,1);
ntt(q,lim,1);
for(int i=0;i<lim;i++) p[i]=(1ll*p[i]*q[i])%MOD;
ntt(p,lim,-1);
int inv=fp(lim, MOD-2);
for(int i=0;i<lim;i++) p[i]=(1ll*inv*p[i])%MOD;
for(int i=1;i<d;i++) b[i]=(1ll*p[i-1]*fp(i,MOD-2))%MOD;b[0]=0;
for(int i=0;i<lim;i++) p[i]=q[i]=0;
}
void exps(int *a,int *b,int d){
if(d==1){
b[0]=1;
return;
}
exps(a,b,(d+1)>>1);
lns(b,u,d);
u[0]=(a[0]+1-u[0]+MOD)%MOD;
for(int i=1;i<d;i++) u[i]=(a[i]-u[i]+MOD)%MOD;
int lim=1,l=0;
while(lim<(d<<1)) lim<<=1,l++;
for(int i=1;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
ntt(b,lim,1);
ntt(u,lim,1);
for(int i=0;i<lim;i++) b[i]=(1ll*b[i]*u[i])%MOD;
ntt(b,lim,-1);
int inv=fp(lim, MOD-2);
for(int i=0;i<lim;i++) b[i]=(1ll*inv*b[i])%MOD;
for(int i=d;i<lim;i++) u[i]=b[i]=0;
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
exps(a,b,n);
for(int i=0;i<n;i++) printf("%d ",b[i]);
return 0;
}
多项式快速幂
#include <bits/stdc++.h>
using namespace std;
const int N=1e7+6;
const int MOD=998244353;
const int G=3;
const int GI=332748118;
int n,m,k;
int a[N],b[N],c[N],r[N],g[N],p[N],q[N],u[N],v[N];
int read(){
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=(1ll*x*10+c-48)%MOD,c=getchar();
return x*f;
}
int fp(int a,int r){
int res=1;
for(;r;r>>=1){
if(r&1) res=(1ll*res*a)%MOD;
a=(1ll*a*a)%MOD;
}
return res;
}
void ntt(int *a,int lim,int t){
for(int i=0;i<lim;i++) if(i<r[i]) swap(a[i],a[r[i]]);
for(int i=1;i<lim;i<<=1){
int wn=fp(t==1?G:GI,(MOD-1)/(i<<1));
for(int j=0;j<lim;j+=(i<<1)){
int w=1;
for(int k=0;k<i;k++,w=(1ll*w*wn)%MOD){
int x=a[j+k];
int y=(1ll*w*a[j+k+i])%MOD;
a[j+k]=(1ll*x+y)%MOD;
a[j+k+i]=(1ll*x-y+MOD)%MOD;
}
}
}
}
void invs(int d,int* a,int* b){
if(d==1){
b[0]=fp(a[0],MOD-2);
return;
}
invs((d+1)>>1,a,b);
int lim=1,l=0;
while(lim<(d<<1)) lim<<=1,l++;
for(int i=1;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
for(int i=0;i<lim;i++) c[i]=a[i];
for(int i=d;i<lim;i++) c[i]=0;
ntt(c,lim,1);
ntt(b,lim,1);
for(int i=0;i<lim;i++) b[i]=(2-1ll*c[i]*b[i]%MOD+MOD)%MOD*b[i]%MOD;
ntt(b,lim,-1);
int inv=fp(lim, MOD-2);
for(int i=0;i<lim;i++) b[i]=(1ll*inv*b[i])%MOD;
for(int i=d;i<lim;i++) b[i]=0;
}
void lns(int *a,int *b,int d){
for(int i=1;i<d;i++) p[i-1]=(1ll*i*a[i])%MOD;p[d-1]=0;
invs(d,a,q);
int lim=1,l=0;
while(lim<(d<<1)) lim<<=1,l++;
for(int i=1;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
ntt(p,lim,1);
ntt(q,lim,1);
for(int i=0;i<lim;i++) p[i]=(1ll*p[i]*q[i])%MOD;
ntt(p,lim,-1);
int inv=fp(lim, MOD-2);
for(int i=0;i<lim;i++) p[i]=(1ll*inv*p[i])%MOD;
for(int i=1;i<d;i++) b[i]=(1ll*p[i-1]*fp(i,MOD-2))%MOD;b[0]=0;
for(int i=0;i<lim;i++) p[i]=q[i]=0;
}
void exps(int *a,int *b,int d){
if(d==1){
b[0]=1;
return;
}
exps(a,b,(d+1)>>1);
lns(b,u,d);
u[0]=(a[0]+1-u[0]+MOD)%MOD;
for(int i=1;i<d;i++) u[i]=(a[i]-u[i]+MOD)%MOD;
int lim=1,l=0;
while(lim<(d<<1)) lim<<=1,l++;
for(int i=1;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
ntt(b,lim,1);
ntt(u,lim,1);
for(int i=0;i<lim;i++) b[i]=(1ll*b[i]*u[i])%MOD;
ntt(b,lim,-1);
int inv=fp(lim, MOD-2);
for(int i=0;i<lim;i++) b[i]=(1ll*inv*b[i])%MOD;
for(int i=d;i<lim;i++) u[i]=b[i]=0;
}
void fps(int *a,int *b,int d){
lns(a,b,d);
for(int i=0;i<d;i++) b[i]=(1ll*b[i]*k)%MOD;
for(int i=0;i<d;i++) a[i]=0;
exps(b,a,d);
}
int main(){
n=read();k=read();
for(int i=0;i<n;i++) a[i]=read();
fps(a,b,n);
for(int i=0;i<n;i++) printf("%d ",a[i]);
return 0;
}