板题:
一. 洛谷4238:
模998244353,NTT:
#include<cstdio>
#include<algorithm>
#define maxn 400005
#define LL long long
using namespace std;
const int mod = 998244353, G = 3;
LL wn,w;
inline LL ksm(LL a,LL b){
LL s=1;
for(;b;b>>=1,a=a*a%mod) if(b&1) s=s*a%mod;
return s;
}
inline void change(LL *a,int len)
{
for(int i=1,j=len/2,k;i<len-1;i++)
{
if(i<j) swap(a[i],a[j]);
for(k=len/2;j>=k;j-=k,k>>=1);
j+=k;
}
}
inline void ntt(LL *a,int len,int flg)
{
change(a,len);
for(int i=2;i<=len;i<<=1)
{
if(flg==1) wn=ksm(G,(mod-1)/i);
else wn=ksm(G,mod-1-(mod-1)/i);
for(int j=0;j<len;j+=i)
{
w=1;
for(int k=j;k<j+i/2;k++)
{
LL u=a[k],v=w*a[k+i/2]%mod;
a[k]=(u+v)%mod,a[k+i/2]=(u-v+mod)%mod;
w=w*wn%mod;
}
}
}
if(flg==-1){
LL ni=ksm(len,mod-2);
for(int i=0;i<len;i++) a[i]=a[i]*ni%mod;
}
}
int n,len;
LL a[maxn],b[maxn],tmp[maxn];
inline void poly_inv(int n,LL *a,LL *b)
{
if(n==1) {b[0]=ksm(a[0],mod-2);return;}
poly_inv((n+1)>>1,a,b);
len=1;while(len<n+n-1) len<<=1;
for(int i=0;i<len;i++) tmp[i]=i<n?a[i]:0;
ntt(tmp,len,1),ntt(b,len,1);
for(int i=0;i<len;i++) {b[i]=(2-tmp[i]*b[i]%mod)*b[i]%mod;if(b[i]<0) b[i]+=mod;}
ntt(b,len,-1);
for(int i=n;i<len;i++) b[i]=0;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%lld",&a[i]);
poly_inv(n,a,b);
for(int i=0;i<n;i++) printf("%lld%c",b[i],i==n-1?10:32);
}
二. 洛谷4239
模109+7,拆系数FFT(7次fft版本)
// luogu-judger-enable-o2
#include<cstdio>
#include<cmath>
#include<algorithm>
#define maxn 400005
#define LL long long
using namespace std;
const int mod = 1e9+7, M1 = 31623, M2 = 14122;
const double Pi = acos(-1);
struct complex
{
double r,i;
complex(double _r=0,double _i=0):r(_r),i(_i){}
complex operator + (const complex &t)const{return complex(r+t.r,i+t.i);}
complex operator - (const complex &t)const{return complex(r-t.r,i-t.i);}
complex operator * (const complex &t)const{return complex(r*t.r-i*t.i,r*t.i+i*t.r);}
complex conj(){return complex(r,-i);}
}w[20][maxn/2];
inline void change(complex *a,int len)
{
for(int i=1,j=len/2,k;i<len-1;i++)
{
if(i<j) swap(a[i],a[j]);
for(k=len/2;j>=k;j-=k,k>>=1);
j+=k;
}
}
inline void fft(complex *a,int len,int flg)
{
change(a,len);
for(int i=2,o=0;i<=len;i<<=1,o++)
for(int j=0;j<len;j+=i)
for(int k=j;k<j+i/2;k++)
{
complex u=a[k],v=(flg==1?w[o][k-j]:w[o][k-j].conj())*a[k+i/2];
a[k]=u+v,a[k+i/2]=u-v;
}
if(flg==-1) for(int i=0;i<len;i++) a[i].r/=len;
}
inline void MTT(int *a,int *b,int n,int *ret)
{
static complex A[maxn],B[maxn],C[maxn],D[maxn],rt[3][maxn];
int len=1;while(len<n+n-1) len<<=1;
for(int i=0;i<len;i++)
if(i<n)
{
A[i]=a[i]/M1,B[i]=a[i]%M1;
C[i]=b[i]/M1,D[i]=b[i]%M1;
}
else A[i]=B[i]=C[i]=D[i]=0;
fft(A,len,1),fft(B,len,1),fft(C,len,1),fft(D,len,1);
for(int i=0;i<len;i++) rt[2][i]=A[i]*C[i],rt[1][i]=A[i]*D[i]+B[i]*C[i],rt[0][i]=B[i]*D[i];
fft(rt[0],len,-1),fft(rt[1],len,-1),fft(rt[2],len,-1);
for(int i=0;i<n;i++) ret[i]=((llround(rt[0][i].r)%mod+llround(rt[1][i].r)*M1%mod)%mod+llround(rt[2][i].r)*M2%mod)%mod;
}
inline int ksm(int a,int b){
int s=1;
for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) s=1ll*s*a%mod;
return s;
}
int n,a[maxn],b[maxn],tmp[maxn];
inline void poly_inv(int n,int *a,int *b)
{
if(n==1) {b[0]=ksm(a[0],mod-2);return;}
poly_inv((n+1)>>1,a,b);
MTT(a,b,n,tmp);
MTT(b,tmp,n,tmp);
for(int i=0;i<n;i++) b[i]=(2*b[i]%mod-tmp[i]+mod)%mod;
}
int main()
{
scanf("%d",&n);int len=1;while(len<n+n-1) len<<=1;
for(int i=2,o=0;i<=len;i<<=1,o++)
for(int j=0;j<i/2;j++)
w[o][j]=complex(cos(2*Pi*j/i),sin(2*Pi*j/i));
for(int i=0;i<n;i++) scanf("%d",&a[i]);
poly_inv(n,a,b);
for(int i=0;i<n;i++) printf("%d%c",b[i],i==n-1?10:32);
}
FFT(4次fft版本)
算法解析可以看这两篇
↓
\darr
↓(膜拜大佬)
Miskcoo’s Space
Clin233
#include<cstdio>
#include<cmath>
#include<algorithm>
#define maxn 400005
#define LL long long
using namespace std;
const int mod = 1e9+7, M = (1<<15)-1;
const double Pi = acos(-1);
struct complex
{
double r,i;
complex(double _r=0,double _i=0):r(_r),i(_i){}
complex operator + (const complex &t)const{return complex(r+t.r,i+t.i);}
complex operator - (const complex &t)const{return complex(r-t.r,i-t.i);}
complex operator * (const complex &t)const{return complex(r*t.r-i*t.i,r*t.i+i*t.r);}
complex conj(){return complex(r,-i);}
}w[20][maxn/2];
inline void change(complex *a,int len)
{
for(int i=1,j=len/2,k;i<len-1;i++)
{
if(i<j) swap(a[i],a[j]);
for(k=len/2;j>=k;j-=k,k>>=1);
j+=k;
}
}
inline void fft(complex *a,int len,int flg)
{
change(a,len);
for(int i=2,o=0;i<=len;i<<=1,o++)
for(int j=0;j<len;j+=i)
for(int k=j;k<j+i/2;k++)
{
complex u=a[k],v=(flg==1?w[o][k-j]:w[o][k-j].conj())*a[k+i/2];
a[k]=u+v,a[k+i/2]=u-v;
}
if(flg==-1) for(int i=0;i<len;i++) a[i].r/=len,a[i].i/=len;//注意这里的虚部也要除
}
inline void MTT(int *a,int *b,int n,int *ret)
{
static complex A[maxn],B[maxn],rt[2][maxn],da,db,dc,dd;
int len=1;while(len<n+n-1) len<<=1;
for(int i=0;i<len;i++)
if(i<n) A[i]=complex(a[i]>>15,a[i]&M),B[i]=complex(b[i]>>15,b[i]&M);
else A[i]=B[i]=0;
fft(A,len,1),fft(B,len,1);
for(int i=0,j;i<len;i++)
{
j=(i==0?0:len-i);
da=(A[i]+A[j].conj())*complex(0.5,0);
db=(A[i]-A[j].conj())*complex(0,-0.5);
dc=(B[i]+B[j].conj())*complex(0.5,0);
dd=(B[i]-B[j].conj())*complex(0,-0.5);
rt[0][i]=da*dc+db*dd*complex(0,1),rt[1][i]=db*dc+da*dd*complex(0,1);
}
fft(rt[0],len,-1),fft(rt[1],len,-1);
for(int i=0;i<n;i++) ret[i]=((llround(rt[0][i].r)%mod<<30)+llround(rt[0][i].i)+((llround(rt[1][i].r)+llround(rt[1][i].i))%mod<<15))%mod;
}
inline int ksm(int a,int b){
int s=1;
for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) s=1ll*s*a%mod;
return s;
}
int n,a[maxn],b[maxn],tmp[maxn];
inline void poly_inv(int n,int *a,int *b)
{
if(n==1) {b[0]=ksm(a[0],mod-2);return;}
poly_inv((n+1)>>1,a,b);
MTT(a,b,n,tmp);
MTT(b,tmp,n,tmp);
for(int i=0;i<n;i++) b[i]=(2*b[i]%mod-tmp[i]+mod)%mod;
}
int main()
{
scanf("%d",&n);int len=1;while(len<n+n-1) len<<=1;
for(int i=2,o=0;i<=len;i<<=1,o++)
for(int j=0;j<i/2;j++)
w[o][j]=complex(cos(2*Pi*j/i),sin(2*Pi*j/i));
for(int i=0;i<n;i++) scanf("%d",&a[i]);
poly_inv(n,a,b);
for(int i=0;i<n;i++) printf("%d%c",b[i],i==n-1?10:32);
}
或者还有个优化版,change改成了用r[],预处理单位根改成O(n),空间小了很多
wlen=1;while(wlen<n+n-1) wlen<<=1;
for(int i=0;i<wlen;i++) w[i]=complex(cos(2*Pi*i/wlen),sin(2*Pi*i/wlen));
for(int i=0;i<len;i++) r[i]=(r[i>>1]>>1)|(i&1?len>>1:0);
int r[maxn],wlen;
inline void fft(complex *a,int len,int flg)
{
for(int i=0;i<len;i++) if(i<r[i]) swap(a[i],a[r[i]]);
for(int i=2;i<=len;i<<=1)
for(int j=0,t=wlen/i;j<len;j+=i)//t=wlen/i
for(int k=j,o=0;k<j+i/2;k++,o+=t)
{
complex u=a[k],v=(flg==1?w[o]:w[o].conj())*a[k+i/2];
a[k]=u+v,a[k+i/2]=u-v;
}
if(flg==-1) for(int i=0;i<len;i++) a[i].r/=len,a[i].i/=len;//注意这里的虚部也要除
}
多项式求逆NTT最新版:
#include<bits/stdc++.h>
#define maxn 2200005
using namespace std;
const int mod = 998244353;
typedef vector<int> Poly;
inline int Pow(int a,int b){
int s=1; for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) s=1ll*s*a%mod;
return s;
}
int w[maxn]={1},r[maxn];
inline int add(int a,int b){return (a+=b)>mod?a-mod:a;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
void NTT(Poly &a,int len,int flg){
a.resize(len);
for(int i=0;i<len;i++) if(i<r[i]) swap(a[i],a[r[i]]);
for(int i=2,l=1,G=flg==1?3:(mod+1)/3;i<=len;i<<=1,l<<=1){
for(int k=l-2,wn=Pow(G,(mod-1)/i);k>=0;k-=2) w[k+1]=1ll*(w[k]=w[k>>1])*wn%mod;
for(int j=0;j<len;j+=i) for(int k=j;k<j+l;k++){
int u=a[k],v=1ll*w[k-j]*a[k+l]%mod;
a[k]=add(u,v),a[k+l]=dec(u,v);
}
}
if(flg==-1) for(int i=0,Inv=Pow(len,mod-2);i<len;i++) a[i]=1ll*a[i]*Inv%mod;
}
Poly Inv(Poly A,int n){
Poly B(1,Pow(A[0],mod-2)),C;
for(int k=2,len=4;k<n<<1;k=len,len<<=1){
C=Poly(A.begin(),A.begin()+min(n,k));
for(int i=0;i<len;i++) r[i]=r[i>>1]>>1|(i&1?len>>1:0);
NTT(C,len,1),NTT(B,len,1);
for(int i=0;i<len;i++) B[i]=1ll*B[i]*(2-1ll*C[i]*B[i]%mod+mod)%mod;
NTT(B,len,-1),B.resize(min(n,k));
}
return B;
}
int n; Poly A;
int main()
{
scanf("%d",&n),A.resize(n);
for(int i=0;i<n;i++) scanf("%d",&A[i]);
Poly B(Inv(A,n));
for(int i=0;i<n;i++) printf("%d%c",B[i],i==n-1?10:32);
}