多项式求逆
给你 f ( x ) f(x) f(x),要求计算 g ( x ) g(x) g(x)满足 f ( x ) g ( x ) ≡ 1 ( m o d x n ) f(x)g(x)\equiv 1(\mod x^n) f(x)g(x)≡1(modxn)
考虑倍增的过程,常数项就直接求逆,否则已经计算完 n 2 \frac{n}{2} 2n的贡献
若已知 f ( x ) h ( x ) ≡ 1 ( m o d x n 2 ) f(x)h(x)\equiv 1 (\mod x^{\frac{n}{2}}) f(x)h(x)≡1(modx2n),则 g ( x ) − h ( x ) ≡ 0 ( m o d x n 2 ) g(x)-h(x)\equiv 0 (\mod x^{\frac{n}{2}}) g(x)−h(x)≡0(modx2n)
平方一下 g 2 ( x ) + h 2 ( x ) − 2 g ( x ) h ( x ) ≡ 0 ( m o d x n ) g^2(x)+h^2(x)-2g(x)h(x)\equiv 0 (\mod x^n) g2(x)+h2(x)−2g(x)h(x)≡0(modxn)
因为这里大于 n 2 \frac{n}{2} 2n的任意一项均至少有一个 0 0 0的贡献,所以可以扩展
移项再把 f ( x ) f(x) f(x)乘进去,我们知道 g ( x ) = 2 h ( x ) − f ( x ) h 2 ( x ) g(x)=2h(x)-f(x)h^2(x) g(x)=2h(x)−f(x)h2(x)
复杂度 n l o g n nlogn nlogn
多项式求导
( x a ) ′ = a x a − 1 (x^a)'=ax^{a-1} (xa)′=axa−1,所以有
f ′ ( x ) = ∑ i ≥ 0 ( i + 1 ) a i + 1 x i f'(x)=\sum_{i\ge 0}(i+1)a_{i+1}x^i f′(x)=∑i≥0(i+1)ai+1xi
多项式积分
是导数的逆运算,不难由上面的结论推导出
∫ x a = 1 a + 1 x a + 1 \int x^a=\frac{1}{a+1}x^{a+1} ∫xa=a+11xa+1,所以有
∫ f ( x ) = ∑ i ≥ 1 a i − 1 i x i \int f(x)=\sum_{i\ge 1}\frac{a_{i-1}}{i}x^i ∫f(x)=∑i≥1iai−1xi
复合函数及其求导法则
形如 f ( g ( x ) ) f(g(x)) f(g(x))的函数,如 f ( x ) = s i n ( c o s ( x ) ) f(x)=sin(cos(x)) f(x)=sin(cos(x))即为复合函数
复合函数求导法则如下
f ′ ( g ( x ) ) = f ′ ( g ( x ) ) g ′ ( x ) f'(g(x))=f'(g(x))g'(x) f′(g(x))=f′(g(x))g′(x),举例如 f ( x ) = l n ( s i n ( x ) ) f(x)=ln(sin(x)) f(x)=ln(sin(x)), l n ′ ( u ) = 1 u ln'(u)=\frac{1}{u} ln′(u)=u1, s i n ′ ( x ) = c o s ( x ) sin'(x)=cos(x) sin′(x)=cos(x),则 f ′ ( x ) = 1 u c o s ( x ) = c o s ( x ) s i n ( x ) f'(x)=\frac{1}{u}cos(x)=\frac{cos(x)}{sin(x)} f′(x)=u1cos(x)=sin(x)cos(x)
泰勒展开与麦克劳林级数
泰勒展开是将在某个点具有 n n n阶导数的函数拟合成多项式的过程,对于在 x 0 x_0 x0处的展开有
f ( x ) = ∑ i f i ( x 0 ) ( x − x 0 ) i i ! + ϕ f(x)=\sum_{i} \frac{f^i(x_0)(x-x_0)^i}{i!}+\phi f(x)=∑ii!fi(x0)(x−x0)i+ϕ
其中 f i ( x ) f^i(x) fi(x)表示在 x x x处的 i i i阶导数,当 n n n趋于无穷时, ϕ \phi ϕ趋于高阶无穷小
麦克劳林级数即为泰勒展开在 0 0 0处的使用,为
f ( x ) = ∑ i f i ( 0 ) x i i ! f(x)=\sum_i{\frac{f^{i}(0)x^i}{i!}} f(x)=∑ii!fi(0)xi
多项式牛顿迭代
已知一个多项式 G ( x ) G(x) G(x),求一个多项式 f ( x ) f(x) f(x),满足 G ( f ( x ) ) ≡ 0 ( m o d x n ) G(f(x))\equiv 0 (\mod x^n) G(f(x))≡0(modxn)
考虑倍增的过程,在 n = 1 n=1 n=1时,我们已经求出 G ( f ( x ) ) ≡ 0 ( m o d x ) G(f(x))\equiv 0(\mod x) G(f(x))≡0(modx)的常数项,现在已经处理完 n 2 \frac{n}{2} 2n的某个多项式 G ( F 0 ( x ) ) G(F_0(x)) G(F0(x))
将 G ( F ( x ) ) G(F(x)) G(F(x))在 G ( F 0 ( x ) ) G(F_0(x)) G(F0(x))处泰勒展开,则有
G ( F ( x ) ) ≡ G ( F 0 ( x ) ) + G ′ ( F o ( x ) ) 1 ! ( F ( x ) − F 0 ( x ) ) + G ′ ′ ( F 0 ( x ) ) 2 ! ( F ( x ) − F 0 ( x ) ) 2 + . . . ( m o d x n ) G(F(x))\equiv G(F_0(x))+\frac{G'(F_o(x))}{1!}(F(x)-F_0(x))+\frac{G''(F_0(x))}{2!}(F(x)-F_0(x))^2+... (\mod x^n) G(F(x))≡G(F0(x))+1!G′(Fo(x))(F(x)−F0(x))+2!G′′(F0(x))(F(x)−F0(x))2+...(modxn)
因为 F ( x ) F(x) F(x)与 F 0 ( x ) F_0(x) F0(x)的前 n 2 \frac{n}{2} 2n项是相同的,所以有贡献的仅有前两项,则有
G ( F ( x ) ) ≡ G ( F 0 ( x ) ) + G ′ ( F o ( x ) ) 1 ! ( F ( x ) − F 0 ( x ) ) G(F(x))\equiv G(F_0(x))+\frac{G'(F_o(x))}{1!}(F(x)-F_0(x)) G(F(x))≡G(F0(x))+1!G′(Fo(x))(F(x)−F0(x))
因为 G ( F ( x ) ) = 0 G(F(x))=0 G(F(x))=0,所以移项可知 F ( x ) ≡ F 0 ( x ) − G ( F 0 ( x ) ) G ′ ( F 0 ( x ) ) ( m o d x n ) F(x)\equiv F_0(x)-\frac{G(F_0(x))}{G'(F_0(x))}(\mod x^n) F(x)≡F0(x)−G′(F0(x))G(F0(x))(modxn)
多项式开方
相当于给出多项式 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) (\mod x^n) B2(x)≡A(x)(modxn)
设多项式 G ( x ) = x 2 − A ( x ) G(x)=x^2-A(x) G(x)=x2−A(x),此处的 A ( x ) A(x) A(x)当作一个整体常数来看
所以我们就相当于要找 G ( B ( x ) ) ≡ 0 ( m o d x n ) G(B(x))\equiv 0 (\mod x^n) G(B(x))≡0(modxn)
用类似倍增的手法,套用牛顿迭代的公式就可以知道
B ( x ) ≡ B 0 ( x ) − G ( B 0 ( x ) ) G ′ ( B 0 ( x ) ) ( m o d x n ) B(x)\equiv B_0(x)-\frac{G(B_0(x))}{G'(B_0(x))}(\mod x^n) B(x)≡B0(x)−G′(B0(x))G(B0(x))(modxn)
我们知道 G ( B 0 ( x ) ) = B 0 2 ( x ) − A ( x ) G(B_0(x))=B_0^2(x)-A(x) G(B0(x))=B02(x)−A(x), G ′ ( B 0 ( x ) ) = 2 B ( x ) G'(B_0(x))=2B(x) G′(B0(x))=2B(x),代入上面的方程就可以知道
B ( x ) ≡ 1 2 ( B 0 ( x ) + A ( x ) B 0 ( x ) ) B(x)\equiv \frac{1}{2}(B_0(x)+\frac{A(x)}{B_0(x)}) B(x)≡21(B0(x)+B0(x)A(x))
套用求逆就可以算了
注意的是常数项仍然需要单独确定,可能需要一个二次剩余,若为 1 1 1时可直接使用
多项式ln及多项式exp的定义
我想了很久这两项的定义到底是啥…
其实应该就是一个与 l n ( x ) , e x ln(x),e^x ln(x),ex的麦克劳林级数复合的过程
注意 l n ( x ) ln(x) ln(x)不能在 x = 0 x=0 x=0时与麦克劳林级数复合,必须 l n ( 1 − x ) ln(1-x) ln(1−x)或 l n ( 1 + x ) ln(1+x) ln(1+x)之类的…
故对于对数函数,设有一个多项式 f ( x ) f(x) f(x),则就有
l n ( 1 − f ( x ) ) = − ∑ i ≥ 1 f i ( x ) i ln(1-f(x))=-\sum_{i\ge1}\frac{f^i(x)}{i} ln(1−f(x))=−∑i≥1ifi(x)
注意此处 f i ( x ) f^i(x) fi(x)不代表 i i i阶导数,仅为普通的次幂
对于指数函数也有同样的定义
e f ( x ) = ∑ i ≥ 0 f i ( x ) i ! e^{f(x)}=\sum_{i\ge0}\frac{f^i(x)}{i!} ef(x)=∑i≥0i!fi(x)
此处同样不代表 i i i阶导数
讲道理不学这个貌似也行的啊…
多项式ln
必须满足常数项为 1 1 1,考虑计算求导后的 l n ( f ( x ) ) ln(f(x)) ln(f(x))的结果,不难发现
l n ′ ( f ( x ) ) = f ′ ( x ) f ( x ) ln'(f(x))=\frac{f'(x)}{f(x)} ln′(f(x))=f(x)f′(x)
故再把右边求导求逆完后积分回去就可以得到 l n ( f ( x ) ) ln(f(x)) ln(f(x))了,此时默认常数项为 0 0 0
多项式exp
貌似很难套用上面的操作…因为 e x e^x ex的导数就是本身…
考虑使用牛顿迭代,我们要求的方程实际上是 h ( x ) = e f ( x ) h(x)=e^{f(x)} h(x)=ef(x)
变形后可知 l n ( h ( x ) ) = f ( x ) ln(h(x))=f(x) ln(h(x))=f(x),将牛迭的构造函数设为 G ( x ) = l n ( x ) − f ( x ) G(x)=ln(x)-f(x) G(x)=ln(x)−f(x),此时 G ′ ( h ( x ) ) = 1 h ( x ) G'(h(x))=\frac{1}{h(x)} G′(h(x))=h(x)1
故根据牛迭的式子,我们有递推
h ( x ) ≡ h 0 ( x ) ( 1 − l n ( h 0 ( x ) ) + f ( x ) ) h(x)\equiv h_0(x)(1-ln(h_0(x))+f(x)) h(x)≡h0(x)(1−ln(h0(x))+f(x))
故求 l n ln ln即可,复杂度为 n l o g n nlogn nlogn
多项式任意次幂
我们有非常 n a i v e naive naive的 n log n log k n\log n \log k nlognlogk的快速幂做法…当然我们会了 l n , e x p ln,exp ln,exp之后就可以有 n log n n \log n nlogn的做法了
考虑 f k ( x ) = ( e l n ( f ( x ) ) ) k = e k l n ( f ( x ) ) f^k(x)=(e^{ln(f(x))})^k=e^{kln(f(x))} fk(x)=(eln(f(x)))k=ekln(f(x))
故求 l n ln ln后乘常数 k k k再求 e x p exp exp即可
注意我们 l n ln ln有特殊限制常数项不为 1 1 1时不能 l n ln ln…
我们有特殊操作,先考虑常数项非 0 0 0时,我们可以使用 f k ( x ) = ( f ( x ) [ x 0 ] ) k [ x 0 ] k f^{k}(x)=(\frac{f(x)}{[x_0]})^k[x_0]^k fk(x)=([x0]f(x))k[x0]k
否则我们可以将多项式移位,将最低的非零位移到 0 0 0处,之后考虑下标的位置即可
同样用上面的式子做
多项式除法与取模
给你次数界分别为 n n n和 m m m的多项式 A A A和 B B B,要求求出满足以下式子的多项式 C C C和 D D D
A ( x ) = B ( x ) C ( x ) + D ( x ) A(x)=B(x)C(x)+D(x) A(x)=B(x)C(x)+D(x)
其中 d e g ( C ) ≤ n − m , d e g ( D ) ≤ m − 1 deg(C)\leq n-m,deg(D)\leq m-1 deg(C)≤n−m,deg(D)≤m−1
比较麻烦的是 D ( x ) D(x) D(x),如果我们能找到一个限制把 D ( x ) D(x) D(x)去掉那么就可以直接求 B B B的逆做出 C C C,特殊情况就是 D = 0 D=0 D=0此时直接求逆就可以得到了…
考虑做一些特殊操作,定义一个运算 A R ( x ) = x n A ( 1 x ) A^{R}(x)=x^nA(\frac{1}{x}) AR(x)=xnA(x1),即将多项式系数翻转
现在我们用 1 x \frac{1}{x} x1代入回上式,可以发现 A ( 1 x ) = B ( 1 x ) C ( 1 x ) + D ( 1 x ) A(\frac{1}{x})=B(\frac{1}{x})C(\frac{1}{x})+D(\frac{1}{x}) A(x1)=B(x1)C(x1)+D(x1)
两边同时乘 x n x^n xn得到, x n A ( 1 x ) = x m B ( 1 x ) x n − m C ( 1 x ) + x n − m + 1 x m − 1 D ( 1 x ) x^nA(\frac{1}{x})=x^mB(\frac{1}{x})x^{n-m}C(\frac{1}{x})+x^{n-m+1}x^{m-1}D(\frac{1}{x}) xnA(x1)=xmB(x1)xn−mC(x1)+xn−m+1xm−1D(x1)
整理得 A R ( x ) = B R ( x ) C R ( x ) + x n − m + 1 D R ( x ) A^R(x)=B^R(x)C^R(x)+x^{n-m+1}D^R(x) AR(x)=BR(x)CR(x)+xn−m+1DR(x)
好玩的事情来了,我们发现乘了 x n − m + 1 x^{n-m+1} xn−m+1后 D R ( x ) D^R(x) DR(x)的最低项变为了 x n − m + 1 x^{n-m+1} xn−m+1,又因为 d e g ( C ) deg(C) deg(C)原本就不超过 n − m n-m n−m,翻转后 d e g ( C R ) deg(C^R) deg(CR) 仍然不超过 n − m n-m n−m,其它两式都是已知的,所以上式在 m o d x n − m + 1 \mod x^{n-m+1} modxn−m+1情况下可以将 D R D^R DR的贡献给去掉…所以改写为
A R ( x ) ≡ B R ( x ) C R ( x ) m o d x n − m + 1 A^R(x)\equiv B^R(x)C^R(x) \mod x^{n-m+1} AR(x)≡BR(x)CR(x)modxn−m+1
在这个模下求逆得到 C R ( x ) C^R(x) CR(x),翻转回来再代入 1 1 1式可以减出来 D ( x ) D(x) D(x)
多项式多点求值
更高妙的东西…
给一个多项式 A ( x ) A(x) A(x)与一些 x i x_i xi,要求出每个 x i x_i xi在这个多项式上的取值
显然的做法就是秦九韶展开…nm大暴力信仰就能过
我们考虑分治…这里每次将 x i x_i xi分成两份,然后考虑如何将多项式的次幂也降下来
一份是 [ 1 , n 2 ] [1,\frac{n}{2}] [1,2n]另一份是 [ n 2 + 1 , n ] [\frac{n}{2}+1,n] [2n+1,n],我们构造两个多项式 L ( x ) L(x) L(x)与 R ( x ) R(x) R(x)
其中 L ( x ) = Π x = 1 n 2 ( x − x i ) L(x)=\Pi_{x=1}^{\frac{n}{2}}(x-x_i) L(x)=Πx=12n(x−xi), R ( x ) = Π x = n 2 + 1 n ( x − x i ) R(x)=\Pi _{x=\frac{n}{2}+1}^{n} (x-x_i) R(x)=Πx=2n+1n(x−xi)
显然我们可以知道,左半边的 x i x_i xi代入 L ( x ) L(x) L(x)均为 0 0 0,右半边代入 R ( x ) R(x) R(x)也均为 0 0 0
对于当前的多项式 A ( x ) A(x) A(x),左边我们让他对 L ( x ) L(x) L(x)取模并分治下去,右边让他对 R ( x ) R(x) R(x)取模并分治下去
容易发现这样每次多项式的次数都不会超过当前这个区间内的点数,所以每次至少减少一半
过程只需要一个多项式取模
然后就赢了…复杂度 n l o g 2 n nlog^2n nlog2n大常数…
L ( x ) , R ( x ) L(x),R(x) L(x),R(x)可以在一开始一个分治 N T T NTT NTT求出来,用类似线段树的结构开个 v e c t o r vector vector存就好了…
板子
基本都封装好了…应该不会出现套上去冲突的情况
开根没有套二次剩余,大概是唯一不足?
upd:重写了一份vector的版本… 感觉真是写的无敌爽
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#include<assert.h>
#include<chrono>
#include<random>
#include<iostream>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
#define SZ(x) ((int)x.size())
#define VI vector<int>
using namespace std;
mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
inline LL read()
{
LL f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int stack[20];
template<typename T>inline void write(T x)
{
if(x<0){putchar('-');x=-x;}
if(!x){putchar('0');return;}
int top=0;
while(x)stack[++top]=x%10,x/=10;
while(top)putchar(stack[top--]+'0');
}
template<typename T>inline void pr1(T x){write(x);putchar(' ');}
template<typename T>inline void pr2(T x){write(x);putchar('\n');}
template<typename T>inline void chkmin(T &x,T y){x=x<y?x:y;}
template<typename T>inline void chkmax(T &x,T y){x=x>y?x:y;}
const int MAXN=100005;
const int mod=998244353;
namespace Poly
{
inline pair<int,pair<int,int>> readmo()
{
int u1=0,u2=0,u3=0;char ch=getchar();
while(ch<'0'||ch>'9'){ch=getchar();}
while(ch>='0'&&ch<='9')
{
u1=(1LL*u1*10+ch-'0')%mod;
u2=(1LL*u2*10+ch-'0')%(mod-1);
if(u3<=1e7)u3=1LL*u3*10+ch-'0';
ch=getchar();
}
return mp(u1,mp(u2,u3));
}
inline int pow_mod(int a,int b)
{
int ret=1;
for(;b;b>>=1,a=1LL*a*a%mod)if(b&1)ret=1LL*ret*a%mod;
return ret;
}
inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
inline void ad(int &x,int y){x+=y;if(x>=mod)x-=mod;}
inline void dl(int &x,int y){x-=y;if(x<0)x+=mod;}
vector<int> wn[25];
int invp[MAXN*4];
inline void init_all()
{
invp[1]=1;for(int i=2;i<MAXN*4;i++)invp[i]=1LL*(mod-mod/i)*invp[mod%i]%mod;
for(int i=1,t=0;i<MAXN*4;i<<=1,++t)
{
int w1=pow_mod(3,(mod-1)/(i<<1));wn[t].resize(i);
for(int j=0,u=1;j<i;j++,u=1LL*u*w1%mod)wn[t][j]=u;
}
}
int R[MAXN*4],L;
inline int NTTinit(int n,int m)
{
int ret;L=0;
for(ret=1;ret<n+m-1;ret<<=1)++L;
for(int i=0;i<ret;i++)R[i]=(R[i>>1]>>1)|(i&1)<<(L-1);
return ret;
}
/*inline void NTT(int *y,int len,int on)
{
for(int i=0;i<len;i++)if(i<R[i])swap(y[i],y[R[i]]);
for(int i=1,t=0;i<len;i<<=1,++t)for(int j=0;j<len;j+=(i<<1))for(int k=0;k<i;k++)
{
int u=y[j+k],v=1LL*y[j+k+i]*wn[t][k]%mod;
y[j+k]=add(u,v);y[j+k+i]=dec(u,v);
}if(on==-1)
{
reverse(y+1,y+len);
for(int i=0,temp=pow_mod(len,mod-2);i<len;i++)y[i]=1LL*y[i]*temp%mod;
}
}*/
inline void NTT(int *y,int len,int on)
{
if(len==1)return ;
for(int i=0;i<len;i++)if(i<R[i])swap(y[i],y[R[i]]);
for(int i=0;i<len;i+=2){LL u=y[i],v=y[i+1];y[i]=add(u,v);y[i+1]=dec(u,v);}
if(len>=4)
{
int now=wn[1][1];
for(int i=0;i<len;i+=4)
{
LL u1=y[i],u2=y[i+2];
LL t1=y[i+1],t2=1LL*y[i+3]*now%mod;
y[i]=add(u1,u2);y[i+2]=dec(u1,u2);
y[i+1]=add(t1,t2);y[i+3]=dec(t1,t2);
}
}
for(int i=4,t=2;i<len;i<<=1,t++)for(int j=0,g=(i<<1);j<len;j+=g)for(int k=0,k2=i;k<i;k+=4,k2+=4)
{
int u1=y[j+k],u2=1LL*y[j+k2]*wn[t][k]%mod;
int v1=y[j+k+1],v2=1LL*y[j+k2+1]*wn[t][k+1]%mod;
int w1=y[j+k+2],w2=1LL*y[j+k2+2]*wn[t][k+2]%mod;
int t1=y[j+k+3],t2=1LL*y[j+k2+3]*wn[t][k+3]%mod;
y[j+k]=add(u1,u2);y[j+k2]=dec(u1,u2);
y[j+k+1]=add(v1,v2);y[j+k2+1]=dec(v1,v2);
y[j+k+2]=add(w1,w2);y[j+k2+2]=dec(w1,w2);
y[j+k+3]=add(t1,t2);y[j+k2+3]=dec(t1,t2);
}if(on==-1)
{
reverse(y+1,y+len);LL temp=pow_mod(len,mod-2);
for(int i=0;i<len;i++)y[i]=1LL*y[i]*temp%mod;
}
}
int A[MAXN*4],B[MAXN*4];
inline void clr(int *y,int len){for(int i=0;i<len;i++)y[i]=0;}
inline VI mul(const VI &a,const VI &b)
{
int n=SZ(a),m=SZ(b),ln=NTTinit(n,m);clr(A,ln);clr(B,ln);
for(int i=0;i<n;i++)A[i]=a[i];for(int i=0;i<m;i++)B[i]=b[i];
NTT(A,ln,1);NTT(B,ln,1);for(int i=0;i<ln;i++)A[i]=1LL*A[i]*B[i]%mod;NTT(A,ln,-1);
VI ret;ret.resize(n+m-1);for(int i=0;i<n+m-1;i++)ret[i]=A[i];return ret;
}
VI getinv(const VI &a,int len)
{
if(len==1)return VI(1,pow_mod(a[0],mod-2));VI b=getinv(a,len>>1);
clr(A,len<<1);clr(B,len<<1);
for(int i=0,z=min(SZ(a),len);i<z;i++)A[i]=a[i];
for(int i=0,z=min(SZ(b),len);i<z;i++)B[i]=b[i];int ln=NTTinit(len,len);
NTT(A,ln,1);NTT(B,ln,1);for(int i=0;i<(len<<1);i++)A[i]=1LL*B[i]*(2-1LL*A[i]*B[i]%mod+mod)%mod;NTT(A,ln,-1);
b.resize(len);for(int i=0;i<len;i++)b[i]=A[i];return b;
}
inline int getlen(int z){int ret;for(ret=1;ret<z;ret<<=1);return ret;}
inline VI Iv(const VI &a){return getinv(a,getlen(SZ(a)));}
inline void getji(VI &a){a.resize(SZ(a)+1);for(int i=SZ(a)-1;i>=1;i--)a[i]=1LL*a[i-1]*invp[i]%mod;a[0]=0;}
inline void getdao(VI &a){for(int i=0;i<SZ(a)-1;i++)a[i]=1LL*a[i+1]*(i+1)%mod;a.resize(SZ(a)-1);}
inline VI getln(const VI &a){VI u=a;getdao(u);VI b=Iv(a);u=mul(u,b);getji(u);u.resize(SZ(a));return u;}
inline VI Ln(const VI &a,int len){VI b=a;b.resize(len);return getln(b);}
VI getexp(const VI &a,int len)
{
if(len==1){return VI(1,1);}VI b=getexp(a,len>>1);b.resize(len);VI c=getln(b);
for(int i=0,z=SZ(a);i<len;i++)c[i]=(i<z?add(mod-c[i],a[i]):mod-c[i]);ad(c[0],1);
b=mul(b,c);b.resize(len);return b;
}
inline VI Exp(const VI &a){return getexp(a,getlen(SZ(a)));}
inline void Rev(VI &a){reverse(a.begin(),a.end());}
inline VI getdiv(const VI &a,const VI &b)
{
VI u=a,v=b;Rev(u);Rev(v);u.resize(SZ(u)-SZ(v)+1);v.resize(SZ(u));
u=mul(u,Iv(v));u.resize(SZ(v));Rev(u);return u;
}
inline VI getmod(const VI &a,const VI &b)
{
if(SZ(a)<SZ(b))return a;
VI z=getdiv(a,b);z=mul(z,b);z.resize(SZ(a));
for(int i=0;i<SZ(a);i++)z[i]=dec(a[i],z[i]);
while(SZ(z)&&!z.back())z.pop_back();return z;
}
inline VI getpow(const VI &a,int k)
{
VI z=Ln(a,getlen(SZ(a)));
for(int i=0;i<SZ(z);i++)z[i]=1LL*z[i]*k%mod;
return Exp(z);
}
inline VI kthpow(VI a,int k1,int k2,int k3)
{
int z=-1,lamb,n=SZ(a);
for(int i=0;i<SZ(a);i++)if(a[i]){z=i;break;}if(z==-1)return VI(SZ(a),0);
if(1LL*z*k3>=SZ(a))return VI(SZ(a),0);
for(int i=0;i+z<SZ(a);i++)a[i]=a[i+z];a.resize(SZ(a)-z);lamb=a[0];
for(int i=0,temp=pow_mod(a[0],mod-2);i<SZ(a);i++)a[i]=1LL*a[i]*temp%mod;
a=getpow(a,k1);VI b(n);lamb=pow_mod(lamb,k2);
for(int i=0;i<z*k1;i++)b[i]=0;
for(int i=z*k1;i<n;i++)b[i]=1LL*a[i-z*k1]*lamb%mod;return b;
}
}
namespace Multipnt
{
inline void ad(int &x,int y){x+=y;if(x>=mod)x-=mod;}
inline void dl(int &x,int y){x-=y;if(x<0)x+=mod;}
#define lc now<<1
#define rc now<<1|1
VI vec[MAXN*4],poly[MAXN*4],f,g,a;
void init_all_poly(int now,int l,int r)
{
if(l==r){vec[now].resize(2);vec[now][0]=mod-a[l];vec[now][1]=1;return ;}
int mid=(l+r)/2;init_all_poly(lc,l,mid);init_all_poly(rc,mid+1,r);
vec[now]=Poly::mul(vec[lc],vec[rc]);
}
void divide_and_conquer(int now,int l,int r)
{
if(l==r){g[l]=poly[now][0];return ;}int mid=(l+r)/2;
if(r-l<=128)
{
for(int i=l;i<=r;i++)
{
int sum=0,z=1;
for(auto p:poly[now])ad(sum,1LL*z*p%mod),z=1LL*z*a[i]%mod;
g[i]=sum;
}return ;
}
poly[lc]=Poly::getmod(poly[now],vec[lc]);poly[rc]=Poly::getmod(poly[now],vec[rc]);
divide_and_conquer(lc,l,mid);divide_and_conquer(rc,mid+1,r);
}
void main()
{
int n=read(),m=read();
f.resize(n+1);for(int i=0;i<=n;i++)f[i]=read();
a.resize(m+1);for(int i=1;i<=m;i++)a[i]=read();
init_all_poly(1,1,m);g.resize(m+1);
poly[1]=f;divide_and_conquer(1,1,m);
for(int i=1;i<=m;i++)pr2(g[i]);
}
}
int main()
{
#ifdef Rose
double BeginJudgeTime=clock();
#endif
Poly::init_all();
Multipnt::main();
#ifdef Rose
double EndJudgeTime=clock();
cerr<<"JudgeTime is"<<" ";
cerr<<(EndJudgeTime-BeginJudgeTime)/CLOCKS_PER_SEC<<endl;
#endif
return 0;
}