多项式全家桶

多项式求逆

给你 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)=axa1,所以有

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)=i0(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)=i1iai1xi

复合函数及其求导法则

形如 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)(xx0)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))0modx的常数项,现在已经处理完 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)=x2A(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(1x) 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(1f(x))=i1ifi(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)=i0i!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)(1ln(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)nm,deg(D)m1

比较麻烦的是 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)xnmC(x1)+xnm+1xm1D(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)+xnm+1DR(x)

好玩的事情来了,我们发现乘了 x n − m + 1 x^{n-m+1} xnm+1 D R ( x ) D^R(x) DR(x)的最低项变为了 x n − m + 1 x^{n-m+1} xnm+1,又因为 d e g ( C ) deg(C) deg(C)原本就不超过 n − m n-m nm,翻转后 d e g ( C R ) deg(C^R) deg(CR) 仍然不超过 n − m n-m nm,其它两式都是已知的,所以上式在 m o d    x n − m + 1 \mod x^{n-m+1} modxnm+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)modxnm+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(xxi) 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(xxi)

显然我们可以知道,左半边的 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;
}
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值