- 并没有讲解.只是记录用.
(FFT)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int MAXN=4e6+10;
inline int read()
{
int x=0;
bool pos=1;
char ch=getchar();
for(; !isdigit(ch); ch=getchar())
if(ch=='-')
pos=0;
for(; isdigit(ch); ch=getchar())
x=x*10+ch-'0';
return pos?x:-x;
}
struct cp
{
double x,y;
cp(double xx=0,double yy=0)
{
x=xx;
y=yy;
}
cp operator +(const cp &b) const
{
return cp(x+b.x,y+b.y);
}
cp operator -(const cp &b) const
{
return cp(x-b.x,y-b.y);
}
cp operator *(const cp &b) const
{
return cp(x*b.x-y*b.y,x*b.y+y*b.x);
}
};
const double PI=acos(-1.0);
int rev[MAXN];
void init(int n,int lim)
{
for(int i=0; i<n; ++i)
{
for(int j=0; j<lim; ++j)
if((i>>j)&1)
rev[i]|=1<<(lim-j-1);
}
}
void FFT(cp *a,int n,bool invflag)
{
for(int i=0; i<n; ++i)
{
if(i<rev[i])
swap(a[i],a[rev[i]]);
}
for(int l=2; l<=n; l<<=1)
{
int m=l>>1;
cp wi=cp(cos(2*PI/l),sin(2*PI/l));
if(invflag)
wi=cp(cos(2*PI/l),-sin(2*PI/l));
for(cp *p=a; p!=a+n; p+=l)
{
cp w=cp(1,0);
for(int i=0; i<m; ++i)
{
cp t=w*p[i+m];
p[i+m]=p[i]-t;
p[i]=p[i]+t;
w=w*wi;
}
}
}
if(invflag)
{
for(int i=0; i<n; ++i)
a[i].x/=n,a[i].y/=n;
}
}
int n,m;
cp a[MAXN],b[MAXN];
int main()
{
n=read(),m=read();
++n,++m;
for(int i=0; i<n; ++i)
a[i]=cp((double)read(),0);
for(int i=0; i<m; ++i)
b[i]=cp((double)read(),0);
int N=1,lim=0;
while(N<n+m-1)
N<<=1,++lim;
init(N,lim);
FFT(a,N,false);
FFT(b,N,false);
for(int i=0; i<N; ++i)
a[i]=a[i]*b[i];
FFT(a,N,true);
for(int i=0; i<n+m-1; ++i)
printf("%d ",(int)(a[i].x+0.5));
return 0;
}
(NTT)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int MAXN=4e6+10;
inline int read()
{
int x=0;
bool pos=1;
char ch=getchar();
for(; !isdigit(ch); ch=getchar())
if(ch=='-')
pos=0;
for(; isdigit(ch); ch=getchar())
x=x*10+ch-'0';
return pos?x:-x;
}
const int P=998244353,G=3;
int add(int a,int b)
{
return (a + b) % P;
}
int mul(int a,int b)
{
return 1LL * a * b % P;
}
int fpow(int a,int b)
{
int res=1;
while(b)
{
if(b&1)
res=mul(res,a);
a=mul(a,a);
b>>=1;
}
return res;
}
int inv(int x)
{
return fpow(x,P-2);
}
int rev[MAXN];
void init(int n,int lim)
{
for(int i=0; i<n; ++i)
{
for(int j=0; j<lim; ++j)
if((i>>j)&1)
rev[i]|=1<<(lim-j-1);
}
}
void NTT(int *a,int n,bool invflag)
{
for(int i=0; i<n; ++i)
{
if(i<rev[i])
swap(a[i],a[rev[i]]);
}
for(int l=2; l<=n; l<<=1)
{
int gi=fpow(G,(P-1)/l);
if(invflag)
gi=inv(gi);
int m=l>>1;
for(int *p=a;p!=a+n;p+=l)
{
int g=1;
for(int i=0; i<m; ++i)
{
int t=mul(g,p[i+m]);
p[i+m]=add(p[i],P-t);
p[i]=add(p[i],t);
g=mul(g,gi);
}
}
}
if(invflag)
{
int Invn=inv(n);
for(int i=0; i<n; ++i)
a[i]=mul(a[i],Invn);
}
}
int n,m;
int a[MAXN],b[MAXN];
int main()
{
n=read(),m=read();
++n,++m;
for(int i=0; i<n; ++i)
a[i]=read();
for(int i=0; i<m; ++i)
b[i]=read();
int N=1,lim=0;
while(N<n+m-1)
N<<=1,++lim;
init(N,lim);
NTT(a,N,false);
NTT(b,N,false);
for(int i=0; i<N; ++i)
a[i]=mul(a[i],b[i]);
NTT(a,N,true);
for(int i=0; i<n+m-1; ++i)
printf("%d ",a[i]);
return 0;
}
(FWT)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
{
int out=0,fh=1;
char jp=getchar();
while ((jp>'9'||jp<'0')&&jp!='-')
jp=getchar();
if (jp=='-')
fh=-1,jp=getchar();
while (jp>='0'&&jp<='9')
out=out*10+jp-'0',jp=getchar();
return out*fh;
}
const int P=998244353,inv2=(P+1)>>1;
inline int add(int a,int b)
{
return (a + b) % P;
}
inline int mul(int a,int b)
{
return 1LL * a * b % P;
}
void FWT(int *a,int n,int op)
{
for(int l=2;l<=n;l<<=1)
{
int m=l>>1;
for(int *p=a;p!=a+n;p+=l)
for(int i=0;i<m;++i)
{
int x0=p[i],x1=p[i+m];
if(op==1)//or
p[i]=x0,p[i+m]=add(x0,x1);
else if(op==2)//and
p[i]=add(x0,x1),p[i+m]=x1;
else//xor
p[i]=add(x0,x1),p[i+m]=add(x0,P-x1);
}
}
}
void IFWT(int *a,int n,int op)
{
for(int l=2;l<=n;l<<=1)
{
int m=l>>1;
for(int *p=a;p!=a+n;p+=l)
for(int i=0;i<m;++i)
{
int x0=p[i],x1=p[i+m];
if(op==1)
p[i]=x0,p[i+m]=add(x1,P-x0);
else if(op==2)
p[i]=add(x0,P-x1),p[i+m]=x1;
else
p[i]=mul(add(x0,x1),inv2),p[i+m]=mul(add(x0,P-x1),inv2);
}
}
}
const int MAXN=(1<<17)+10;
int a[MAXN],b[MAXN],c[MAXN];
int main()
{
int n=read();
n=1<<n;
for(int i=0;i<n;++i)
a[i]=read();
for(int i=0;i<n;++i)
b[i]=read();
for(int op=1;op<=3;++op)
{
FWT(a,n,op);
FWT(b,n,op);
for(int i=0;i<n;++i)
c[i]=mul(a[i],b[i]);
IFWT(a,n,op);
IFWT(b,n,op);
IFWT(c,n,op);
for(int i=0;i<n;++i)
printf("%d ",c[i]);
puts("");
}
return 0;
}
三模数 (NTT)
- 取三个具有 (P=pcdot 2^k+1) 形式的模数,在每个模意义下分别求解,最后用 (CRT) 合并.这样做要求最终答案不超过三个模数之积.
拆系数 (FFT)
- 对任意模数 (P) ,记 (m=sqrt P).那么把每个系数写成 (a imes m+b,a,b<m) 的形式,然后乘法分配律分别做,这样每个系数都不会超过 (P) ,最后再合并.
分治 (NTT/FFT)
- 现在要算这样一个形式的卷积:
[f_i=sum_{j=1}^{i}f_{i-j}cdot g_j
]
- 给出初始值 (f_0) 以及 (g) 的所有值,求 (f) 的所有项.
- 如果每次直接做 (NTT/FFT) ,复杂度显然为 (O(n^2logn)) ,爆炸.
- 考虑一个像 (cdq) 分治的东西,即算左边,再算左边对右边的贡献,再算右边,长度为 (1) 时返回.
- 若当前计算区间 ([l,r)) ,就把 (f) 的前 (frac {r-l} 2) 项与 (g) 的前 (r-l) 项做卷积,把答案的后 (frac {r-l} 2) 项加入 (f) 的对应位置.
- 这样做后半段一定是对的,所以就不用关注长度的问题了.时间复杂度为 (O(nlog^2n)) .
分治 (NTT)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline ll read()
{
ll out=0,fh=1;
char jp=getchar();
while ((jp>'9'||jp<'0')&&jp!='-')
jp=getchar();
if (jp=='-')
fh=-1,jp=getchar();
while (jp>='0'&&jp<='9')
out=out*10+jp-'0',jp=getchar();
return out*fh;
}
const int P=998244353,G=3;
inline int add(int a,int b)
{
return (a + b) % P;
}
inline int mul(int a,int b)
{
return 1LL * a * b % P;
}
int fpow(int a,int b)
{
int res=1;
while(b)
{
if(b&1)
res=mul(res,a);
a=mul(a,a);
b>>=1;
}
return res;
}
const int MAXN=2e5+10;
int rev[MAXN],omega[MAXN],inv[MAXN];
void rev_init(int n,int lim)
{
for(int i=0;i<n;++i)
{
int t=0;
for(int j=0;j<lim;++j)
if((i>>j)&1)
t|=1<<(lim-j-1);
rev[i]=t;
}
}
void omega_init(int n)
{
for(int l=2;l<=n;l<<=1)
{
omega[l]=fpow(G,(P-1)/l);
inv[l]=fpow(omega[l],P-2);
}
}
void NTT(int *a,int n,int lim,int invflag)
{
for(int i=0;i<n;++i)
{
if(i<rev[i])
swap(a[i],a[rev[i]]);
}
for(int l=2;l<=n;l<<=1)
{
int m=l>>1;
int gi=omega[l];
if(invflag)
gi=inv[l];
for(int *p=a;p!=a+n;p+=l)
{
int g=1;
for(int i=0;i<m;++i)
{
int t=mul(g,p[i+m]);
p[i+m]=add(p[i],P-t);
p[i]=add(p[i],t);
g=mul(g,gi);
}
}
}
if (invflag)
{
int invn=fpow(n,P-2);
for(int i=0;i<n;++i)
a[i]=mul(a[i],invn);
}
}
int f[MAXN],g[MAXN],a[MAXN],b[MAXN];
void solve(int l,int r,int lim)//[l,r)
{
if(lim<=0)
return;
int mid=(l+r)>>1,len=r-l;
solve(l,mid,lim-1);
rev_init(len,lim);
for(int i=0;i<len/2;++i)
a[i]=f[l+i];
for(int i=len/2;i<len;++i)
a[i]=0;
for(int i=0;i<len;++i)
b[i]=g[i];
NTT(a,len,lim,false);
NTT(b,len,lim,false);
for(int i=0;i<len;++i)
a[i]=mul(a[i],b[i]);
NTT(a,len,lim,true);
for(int i=len/2;i<len;++i)
f[i+l]=add(f[i+l],a[i]);
solve(mid,r,lim-1);
}
int main()
{
int n=read();
f[0]=1;
for(int i=1;i<n;++i)
g[i]=read();
int N=1,lim=0;
while(N<n)
N<<=1,++lim;
omega_init(N);
solve(0,N,lim);
for(int i=0;i<n;++i)
printf("%d ",f[i]);
puts("");
return 0;
}
多项式求逆
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int read()
{
int out=0,sgn=1;
char jp=getchar();
while(jp!='-' && (jp<'0' || jp>'9'))
jp=getchar();
if(jp=='-')
sgn=-1,jp=getchar();
while(jp>='0' && jp<='9')
out=out*10+jp-'0',jp=getchar();
return out*sgn;
}
const int MAXN=4e5+10;
const int P=998244353,G=3;
int add(int a,int b)
{
return (a+b>=P)?(a+b-P):(a+b);
}
int mul(int a,int b)
{
return 1LL * a * b % P;
}
int fpow(int a,int b)
{
int res=1;
while(b)
{
if(b&1)
res=mul(res,a);
a=mul(a,a);
b>>=1;
}
return res;
}
int rev[MAXN],omega[MAXN],inv[MAXN];
int curn;
void init(int n)
{
for(int i=0;i<n;++i)
rev[i]=(rev[i>>1]>>1)|((i&1)*(n>>1));
for(int l=2; l<=n; l<<=1)
{
omega[l]=fpow(G,(P-1)/l);
inv[l]=fpow(omega[l],P-2);
}
curn=n;
}
void DFT(int *a,int n,bool invflag)
{
if(curn!=n)
init(n);
for(int i=0; i<n; ++i)
if(i<rev[i])
swap(a[i],a[rev[i]]);
for(int l=2; l<=n; l<<=1)
{
int m=(l>>1);
int gi=omega[l];
if(invflag)
gi=inv[l];
for(int *p=a; p!=a+n; p+=l)
{
int g=1;
for(int i=0; i<m; ++i)
{
int t=mul(g,p[i+m]);
p[i+m]=add(p[i],P-t);
p[i]=add(p[i],t);
g=mul(g,gi);
}
}
}
if(invflag)
{
int invn=fpow(n,P-2);
for(int i=0; i<n; ++i)
a[i]=mul(a[i],invn);
}
}
int a[MAXN],b[MAXN];
void NTT(int *A,int *B,int *C,int lenA,int lenB)
{
int lenC=lenA+lenB-1,n=1;
while(n<lenC)
n<<=1;
for(int i=0;i<lenA;++i)
a[i]=A[i];
for(int i=lenA;i<n;++i)
a[i]=0;
for(int i=0;i<lenB;++i)
b[i]=B[i];
for(int i=lenB;i<n;++i)
b[i]=0;
DFT(a,n,false);
DFT(b,n,false);
for(int i=0; i<n; ++i)
C[i]=mul(a[i],b[i]);
DFT(C,n,true);
}
int tmp[MAXN];
void poly_inverse(int *A,int *B,int n)
{
B[0]=fpow(A[0],P-2);
int k=0;
for(int i=2;i<=n;i<<=1)
{
++k;
NTT(A,B,tmp,i,i);
NTT(tmp,B,tmp,i,i);
for(int j=0;j<i;++j)
B[j]=add(mul(2,B[j]),P-tmp[j]);
}
}
int poly[MAXN],invpoly[MAXN];
int main()
{
int n=read();
for(int i=0;i<n;++i)
poly[i]=read();
int N=1,lim=0;
while((1<<lim)<n)
++lim,N<<=1;
poly_inverse(poly,invpoly,N);
for(int i=0;i<n;++i)
printf("%d ",invpoly[i]);
puts("");
return 0;
}
多项式除法/多项式取模
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int read()
{
int out=0,sgn=1;
char jp=getchar();
while(jp!='-' && (jp<'0' || jp>'9'))
jp=getchar();
if(jp=='-')
sgn=-1,jp=getchar();
while(jp>='0' && jp<='9')
out=out*10+jp-'0',jp=getchar();
return out*sgn;
}
const int MAXN=4e5+10;
const int P=998244353,G=3;
int add(int a,int b)
{
return (a+b>=P)?(a+b-P):(a+b);
}
int mul(int a,int b)
{
return 1LL * a * b % P;
}
int fpow(int a,int b)
{
int res=1;
while(b)
{
if(b&1)
res=mul(res,a);
a=mul(a,a);
b>>=1;
}
return res;
}
int rev[MAXN],omega[MAXN],inv[MAXN];
int curn;
void init(int n)
{
for(int i=0;i<n;++i)
rev[i]=(rev[i>>1]>>1)|((i&1)*(n>>1));
for(int l=2; l<=n; l<<=1)
{
omega[l]=fpow(G,(P-1)/l);
inv[l]=fpow(omega[l],P-2);
}
curn=n;
}
void DFT(int *a,int n,bool invflag)
{
if(curn!=n)
init(n);
for(int i=0; i<n; ++i)
if(i<rev[i])
swap(a[i],a[rev[i]]);
for(int l=2; l<=n; l<<=1)
{
int m=(l>>1);
int gi=omega[l];
if(invflag)
gi=inv[l];
for(int *p=a; p!=a+n; p+=l)
{
int g=1;
for(int i=0; i<m; ++i)
{
int t=mul(g,p[i+m]);
p[i+m]=add(p[i],P-t);
p[i]=add(p[i],t);
g=mul(g,gi);
}
}
}
if(invflag)
{
int invn=fpow(n,P-2);
for(int i=0; i<n; ++i)
a[i]=mul(a[i],invn);
}
}
int a[MAXN],b[MAXN];
void NTT(int *A,int *B,int *C,int lenA,int lenB)
{
int lenC=lenA+lenB-1,n=1;
while(n<lenC)
n<<=1;
for(int i=0;i<lenA;++i)
a[i]=A[i];
for(int i=lenA;i<n;++i)
a[i]=0;
for(int i=0;i<lenB;++i)
b[i]=B[i];
for(int i=lenB;i<n;++i)
b[i]=0;
DFT(a,n,false);
DFT(b,n,false);
for(int i=0; i<n; ++i)
C[i]=mul(a[i],b[i]);
DFT(C,n,true);
}
int tmp[MAXN];
void poly_inverse(int *A,int *B,int n)
{
for(int i=0;i<2*n;++i)
B[i]=0;
B[0]=fpow(A[0],P-2);
int k=0;
for(int i=2;i<=n;i<<=1)
{
++k;
NTT(A,B,tmp,i,i);
NTT(tmp,B,tmp,i,i);
for(int j=0;j<i;++j)
B[j]=add(mul(2,B[j]),P-tmp[j]);
}
}
void poly_rev(int *A,int n)//n->最高项次数
{
for(int i=0;i<n-i;++i)
swap(A[i],A[n-i]);
}
int InvB[MAXN];
int ModA[MAXN],ModB[MAXN];
void poly_division(int *A,int *B,int *D,int *R,int n,int m)
{
poly_rev(A,n);
poly_rev(B,m);
for(int i=0;i<n-m+1;++i)
ModA[i]=A[i],ModB[i]=B[i];
int N=1;
while(N<n-m+1)
N<<=1;
poly_inverse(ModB,InvB,N);
for(int i=n-m+1;i<N;++i)
InvB[i]=0;
NTT(ModA,InvB,D,n-m+1,n-m+1);
poly_rev(D,n-m);
poly_rev(A,n);
poly_rev(B,m);
NTT(B,D,R,m,n-m+1);
for(int i=0;i<n;++i)
R[i]=add(A[i],P-R[i]);
}
int A[MAXN],B[MAXN],D[MAXN],R[MAXN];
int main()
{
int n=read(),m=read();
for(int i=0;i<=n;++i)
A[i]=read();
for(int i=0;i<=m;++i)
B[i]=read();
poly_division(A,B,D,R,n,m);
for(int i=0;i<n-m+1;++i)
printf("%d ",D[i]);
puts("");
for(int i=0;i<m;++i)
printf("%d ",R[i]);
puts("");
return 0;
}
多项式 (ln)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int read()
{
int out=0,sgn=1;
char jp=getchar();
while(jp!='-' && (jp<'0' || jp>'9'))
jp=getchar();
if(jp=='-')
sgn=-1,jp=getchar();
while(jp>='0' && jp<='9')
out=out*10+jp-'0',jp=getchar();
return out*sgn;
}
const int MAXN=4e5+10;
const int P=998244353,G=3;
int add(int a,int b)
{
return (a+b>=P)?(a+b-P):(a+b);
}
int mul(int a,int b)
{
return 1LL * a * b % P;
}
int fpow(int a,int b)
{
int res=1;
while(b)
{
if(b&1)
res=mul(res,a);
a=mul(a,a);
b>>=1;
}
return res;
}
int rev[MAXN],omega[MAXN],inv[MAXN];
int curn;
void init(int n)
{
for(int i=0;i<n;++i)
rev[i]=(rev[i>>1]>>1)|((i&1)*(n>>1));
for(int l=2; l<=n; l<<=1)
{
omega[l]=fpow(G,(P-1)/l);
inv[l]=fpow(omega[l],P-2);
}
curn=n;
}
void DFT(int *a,int n,bool invflag)
{
if(curn!=n)
init(n);
for(int i=0; i<n; ++i)
if(i<rev[i])
swap(a[i],a[rev[i]]);
for(int l=2; l<=n; l<<=1)
{
int m=(l>>1);
int gi=omega[l];
if(invflag)
gi=inv[l];
for(int *p=a; p!=a+n; p+=l)
{
int g=1;
for(int i=0; i<m; ++i)
{
int t=mul(g,p[i+m]);
p[i+m]=add(p[i],P-t);
p[i]=add(p[i],t);
g=mul(g,gi);
}
}
}
if(invflag)
{
int invn=fpow(n,P-2);
for(int i=0; i<n; ++i)
a[i]=mul(a[i],invn);
}
}
int a[MAXN],b[MAXN];
void NTT(int *A,int *B,int *C,int lenA,int lenB)
{
int lenC=lenA+lenB-1,n=1;
while(n<lenC)
n<<=1;
for(int i=0;i<lenA;++i)
a[i]=A[i];
for(int i=lenA;i<n;++i)
a[i]=0;
for(int i=0;i<lenB;++i)
b[i]=B[i];
for(int i=lenB;i<n;++i)
b[i]=0;
DFT(a,n,false);
DFT(b,n,false);
for(int i=0; i<n; ++i)
C[i]=mul(a[i],b[i]);
DFT(C,n,true);
}
int tmp[MAXN];
void poly_inverse(int *A,int *B,int n)
{
for(int i=0;i<2*n;++i)
B[i]=0;
B[0]=fpow(A[0],P-2);
int k=0;
for(int i=2;i<=n;i<<=1)
{
++k;
NTT(A,B,tmp,i,i);
NTT(tmp,B,tmp,i,i);
for(int j=0;j<i;++j)
B[j]=add(mul(2,B[j]),P-tmp[j]);
}
}
void poly_diff(int *A,int n)
{
for(int i=0;i<n-1;++i)
A[i]=mul(A[i+1],i+1);
}
void poly_int(int *A,int n)
{
for(int i=n;i>=1;--i)
A[i]=mul(A[i-1],fpow(i,P-2));
}
int InvA[MAXN];
void ln(int *A,int *B,int n)
{
poly_inverse(A,InvA,n);
poly_diff(A,n);
NTT(A,InvA,B,n,n);
poly_int(B,n);
B[0]=0;
}
int A[MAXN],B[MAXN];
int main()
{
int n=read();
int N=1;
while(N<n)
N<<=1;
for(int i=0;i<n;++i)
A[i]=read();
ln(A,B,N);
for(int i=0;i<n;++i)
printf("%d ",B[i]);
puts("");
return 0;
}
多项式 (exp)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int read()
{
int out=0,sgn=1;
char jp=getchar();
while(jp!='-' && (jp<'0' || jp>'9'))
jp=getchar();
if(jp=='-')
sgn=-1,jp=getchar();
while(jp>='0' && jp<='9')
out=out*10+jp-'0',jp=getchar();
return out*sgn;
}
const int MAXN=4e5+10;
const int P=998244353,G=3;
int add(int a,int b)
{
return (a+b>=P)?(a+b-P):(a+b);
}
int mul(int a,int b)
{
return 1LL * a * b % P;
}
int fpow(int a,int b)
{
int res=1;
while(b)
{
if(b&1)
res=mul(res,a);
a=mul(a,a);
b>>=1;
}
return res;
}
int rev[MAXN],omega[MAXN],inv[MAXN];
int curn;
void init(int n)
{
for(int i=0;i<n;++i)
rev[i]=(rev[i>>1]>>1)|((i&1)*(n>>1));
for(int l=2; l<=n; l<<=1)
{
omega[l]=fpow(G,(P-1)/l);
inv[l]=fpow(omega[l],P-2);
}
curn=n;
}
void DFT(int *a,int n,bool invflag)
{
if(curn!=n)
init(n);
for(int i=0; i<n; ++i)
if(i<rev[i])
swap(a[i],a[rev[i]]);
for(int l=2; l<=n; l<<=1)
{
int m=(l>>1);
int gi=omega[l];
if(invflag)
gi=inv[l];
for(int *p=a; p!=a+n; p+=l)
{
int g=1;
for(int i=0; i<m; ++i)
{
int t=mul(g,p[i+m]);
p[i+m]=add(p[i],P-t);
p[i]=add(p[i],t);
g=mul(g,gi);
}
}
}
if(invflag)
{
int invn=fpow(n,P-2);
for(int i=0; i<n; ++i)
a[i]=mul(a[i],invn);
}
}
int a[MAXN],b[MAXN];
void NTT(int *A,int *B,int *C,int lenA,int lenB)
{
int lenC=lenA+lenB-1,n=1;
while(n<lenC)
n<<=1;
for(int i=0;i<lenA;++i)
a[i]=A[i];
for(int i=lenA;i<n;++i)
a[i]=0;
for(int i=0;i<lenB;++i)
b[i]=B[i];
for(int i=lenB;i<n;++i)
b[i]=0;
DFT(a,n,false);
DFT(b,n,false);
for(int i=0; i<n; ++i)
C[i]=mul(a[i],b[i]);
DFT(C,n,true);
}
int tmp[MAXN];
void poly_inverse(int *A,int *B,int n)
{
for(int i=0;i<2*n;++i)
B[i]=0;
B[0]=fpow(A[0],P-2);
int k=0;
for(int i=2;i<=n;i<<=1)
{
++k;
NTT(A,B,tmp,i,i);
NTT(tmp,B,tmp,i,i);
for(int j=0;j<i;++j)
B[j]=add(mul(2,B[j]),P-tmp[j]);
}
}
void poly_diff(int *A,int n)
{
for(int i=0;i<n-1;++i)
A[i]=mul(A[i+1],i+1);
}
void poly_int(int *A,int n)
{
for(int i=n;i>=1;--i)
A[i]=mul(A[i-1],fpow(i,P-2));
}
int InvA[MAXN],tmpA[MAXN];
void poly_ln(int *A,int *B,int n)
{
for(int i=0;i<n;++i)
tmpA[i]=A[i];
poly_inverse(tmpA,InvA,n);
poly_diff(tmpA,n);
NTT(tmpA,InvA,B,n,n);
poly_int(B,n);
B[0]=0;
for(int i=0;i<n;++i)
tmpA[i]=0;
}
int lnB[MAXN];
void poly_exp(int *A,int *B,int n)
{
if(n==1)
{
B[0]=1;
return;
}
poly_exp(A,B,n>>1);
for(int i=0;i<n;++i)
lnB[i]=0;
poly_ln(B,lnB,n);
for(int i=0;i<n;++i)
lnB[i]=add(A[i],P-lnB[i]);
lnB[0]=add(lnB[0],1);
NTT(B,lnB,B,n>>1,n);
for(int i=n;i<(n+(n>>1));++i)
B[i]=0;
}
int A[MAXN],B[MAXN];
int main()
{
int n=read();
for(int i=0;i<n;++i)
A[i]=read();
int N=1;
while(N<n)
N<<=1;
poly_exp(A,B,N);
for(int i=0;i<n;++i)
printf("%d ",B[i]);
puts("");
return 0;
}