多项式整理(upd:2022.1.6)

多项式

by AmanoKumiko

1.求逆

需要\([x^0]f(x)≠0\)

\(Tips\)\(O(N^2)\)暴力求逆

\[F(x)G(x)\equiv1(mod\ x^n)\\ H(x)=F(x)G(x)\\ h_n=\sum_{i=0}^nf_ig_{n-i}=0\\ h_0=f_0g_0=1=>f_0=g_0^{-1}\\ f_n=-g_0^{-1}\sum_{i=0}^{n-1}f_ig_{n-i} \]


2.ln

需要\([x^0]f(x)=1\)


3.Exp

需要\([x^0]f(x)=0\)

\(Tips\)\(O(N^2)\)暴力\(exp\)

\[F(x)=exp\ G(x)\\ F'(x)=exp\ G(x)G'(x)\\ xF'(x)=xF(x)G'(x)\\ nf_n=\sum_{i=1}^nig_if_{n-i} \]


4.积化和

即将乘积先取对数再\(exp\)

1.\(-ln(1-x)=\sum_{i=1}^{+∞}\frac{x^i}{i}\)求解

2.形如\(\prod F(ix)\)的复合可以用自然数幂和求解

Problems:

【LuoguP4389】付公主的背包

【LuoguP5850】calc加强版


5.和化积

利用\(ln\)相关导数和\([f(x)±g(x)]'=f'(x)±g'(x)\)将和化为积

Problems:

【LuoguP4705】玩游戏


6.常用模数

1.\(119*2^{23}+1\)

2.\(224*2^{21}+1\)

3.\(479*2^{21}+1\)


7.板子

1.NTT

#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define N 600010
#define mo 998244353
#define LL long long
#define ULL unsigned long long

int rev[N],G1[N],G2[N],fac[N],ifac[N],inv[N];

int mod(int x){return x>=mo?x-mo:x;}

int mi(int x,int y){
	if(!y)return 1;
	if(y==1)return x;
	return y%2?1ll*x*mi(1ll*x*x%mo,y/2)%mo:mi(1ll*x*x%mo,y/2);
}

void init(){
	fac[0]=ifac[0]=1;
	F(i,1,N-10)fac[i]=1ll*fac[i-1]*i%mo,inv[i]=(i==1?1:1ll*mo/i*mod(mo-1ll*inv[mo%i]%mo)%mo);
	ifac[N-10]=mi(fac[N-10],mo-2);
	Fd(i,N-11,1)ifac[i]=1ll*ifac[i+1]*(i+1)%mo;
	for(int l=1;l<=N-10;l<<=1)G1[l]=mi(3,(mo-1)/(l*2)),G2[l]=mi(G1[l],mo-2);
}

void BRT(int x){F(i,0,x-1)rev[i]=(rev[i>>1]>>1)|((i&1)?(x>>1):0);}

struct poly{
	vector<int>val;
	poly(int x=0){if(x)val.push_back(x);}
	poly(const vector<int>&x){val=x;}
	void ins(int x){val.push_back(x);}
	void clear(){vector<int>().swap(val);}
	int sz(){return val.size();}
	void rsz(int x){val.resize(x);}
	void shrink(){for(;sz()&&!val.back();val.pop_back());}
	void Rev(){reverse(val.begin(),val.end());} 
	poly modxn(int x){
		if(val.size()<=x)return poly(val);
		else return poly(vector<int>(val.begin(),val.begin()+x));
	}
	int operator[](int x)const{
		if(x<0||x>=val.size())return 0;
		return val[x];
	}
	void NTT(int x){
		static ULL f[N],w[N];
		w[0]=1;
		F(i,0,sz()-1)f[i]=(((LL)mo<<5)+val[rev[i]])%mo;
		for(int mid=1;mid<sz();mid<<=1){
			int tmp=(x==1?G1[mid]:G2[mid]);
			F(i,1,mid-1)w[i]=w[i-1]*tmp%mo;
			for(int i=0;i<sz();i+=(mid<<1)){
				F(j,0,mid-1){
					int t=w[j]*f[i|j|mid]%mo;
					f[i|j|mid]=f[i|j]+mo-t;f[i|j]+=t;
				}
			}
			//if(mid==(1<<10)){F(i,0,sz()-1)f[i]%=mo;};
		}
		if(x==-1){int tmp=inv[sz()];F(i,0,sz()-1)val[i]=f[i]%mo*tmp%mo;}
		else{F(i,0,sz()-1)val[i]=f[i]%mo;}
	}
	void DFT(){NTT(1);}
	void IDFT(){NTT(-1);}
	friend poly operator*(poly x,poly y){
		if(x.sz()<30||y.sz()<30){
			if(x.sz()>y.sz())swap(x,y);
			poly ret;
			ret.rsz(x.sz()+y.sz());
			F(i,0,ret.sz()-1){
				for(int j=0;j<=i&&j<x.sz();j++)
					ret.val[i]=mod(ret.val[i]+1ll*x[j]*y[i-j]%mo);
			}
	//		ret.shrink();
			return ret;
		}
		int l=1;
		while(l<x.sz()+y.sz()-1)l<<=1;
		x.rsz(l);y.rsz(l);BRT(l);
		x.DFT();y.DFT();
		F(i,0,l-1)x.val[i]=1ll*x[i]*y[i]%mo;
		x.IDFT();
	//	x.shrink();
		return x;
	}
	friend poly operator+(poly x,poly y){
		poly ret;
		ret.rsz(max(x.sz(),y.sz()));
		F(i,0,ret.sz()-1)ret.val[i]=mod(x[i]+y[i]);
		return ret;
	}
	friend poly operator-(poly x,poly y){
		poly ret;
		ret.rsz(max(x.sz(),y.sz()));
		F(i,0,ret.sz()-1)ret.val[i]=mod(x[i]-y[i]+mo);
		return ret;
	}
	poly &operator*=(poly x){return (*this)=(*this)*x;}
	poly &operator+=(poly x){return (*this)=(*this)+x;}
	poly &operator-=(poly x){return (*this)=(*this)-x;}
	poly deriv(){
		poly f;
		f.rsz(sz()-1);
		F(i,0,sz()-2)f.val[i]=1ll*(i+1)*val[i+1]%mo;
		return f;
	}
	poly integ(){
		poly f;
		f.rsz(sz()+1);
		F(i,1,sz())f.val[i]=1ll*val[i-1]*inv[i]%mo;
		return f;
	}
	poly inver(int Len){
		poly f,g,res(mi(val[0],mo-2));
		for(int i=1;i<Len;){
			i<<=1;f.rsz(i);g.rsz(i);BRT(i);
			F(j,0,i-1)f.val[j]=(*this)[j],g.val[j]=res[j];
			f.DFT();g.DFT();
			F(j,0,i-1)f.val[j]=1ll*f[j]*g[j]%mo;
			f.IDFT();
			F(j,0,(i>>1)-1)f.val[j]=0;
			f.DFT();
			F(j,0,i-1)f.val[j]=1ll*f[j]*g[j]%mo;
			f.IDFT();
			res.rsz(i);
			F(j,i>>1,i-1)res.val[j]=mod(mo-f[j]);
		}
		return res.modxn(Len);
	}
	poly Sqrt(int Len){
		int i2=inv[2];
		poly f,g,tmp;
		f.clear();g.clear();
		g.ins(1);
		for(int i=1;i<Len*2;i<<=1){
			int Len=i<<1;
			f.rsz(Len);
			tmp=g.inver(i);
			tmp.rsz(Len);
			BRT(Len);
			F(j,0,i-1)f.val[j]=(j<val.size()?val[j]:0);
			f.DFT();tmp.DFT();
			F(j,0,Len-1)f.val[j]=1ll*f[j]*tmp[j]%mo;
			f.IDFT();
			g.rsz(i);
			F(j,0,i-1)g.val[j]=1ll*i2*mod(g[j]+f[j])%mo;
		}
		return g.modxn(Len);
	}
	poly Ln(int Len){
		return (deriv()*inver(Len)).integ().modxn(Len);
	}
	poly Exp(int Len){
		poly f;
		f.clear();
		f.ins(1);
		for(int i=2;i<Len*2;i<<=1)f=(f*(1-f.Ln(i)+modxn(i))).modxn(i);
		return f.modxn(Len);
	}
	poly Pow(int Len,int k){
		poly f;
		f.clear();
		int tail=0;
		while(val[tail]==0&&tail<sz())tail++;
		if(tail>=sz())return f;
		if(tail*k>=Len)return f;
		f.rsz(Len);
		int Mul=mi(val[tail],mo-2);
		F(i,0,min(Len-1,sz()-tail-1))f.val[i]=1ll*val[i+tail]*Mul%mo;
		Mul=mi(val[tail],k);
		f=f.Ln(Len);
		F(i,0,Len-1)f.val[i]=1ll*f[i]*(k%mo)%mo;
		f=f.Exp(Len);
		Fd(i,Len-1,tail*k)f.val[i]=1ll*f[i-tail*k]*Mul%mo;
		F(i,0,tail*k-1)f.val[i]=0;
		return f;
	}
};

struct Evaluation{
	#define ls x<<1
	#define rs (x<<1)|1
	poly f,g[N],h[N];
	int a[N],b[N],n,m;
	void solve1(int x,int l,int r){
		if(l==r){g[x].rsz(2);g[x].val[0]=1;g[x].val[1]=mod(mo-a[l]);return;}
		int mid=l+r>>1,Len=1;
		solve1(ls,l,mid);solve1(rs,mid+1,r);
		if(r-l+1<=50){
			g[x].rsz(r-l+2);
			F(i,0,r-l+1){
				ULL s=0;
				F(j,0,mid-l+1)s+=1ll*g[ls][j]*g[rs][i-j]%mo;
				g[x].val[i]=s%mo;
			}
		}else{
			while(Len<r-l+1+1)Len<<=1;BRT(Len);
			poly A=g[ls],B=g[rs];
			A.rsz(Len);B.rsz(Len);
			A.DFT();B.DFT();
			F(i,0,Len-1)A.val[i]=1ll*A[i]*B[i]%mo;
			A.IDFT();
			g[x]=A.modxn(r-l+2);
		}
	}
	void solve2(int x,int l,int r){
		if(l==r){b[l]=h[x][0];return;}
		int mid=l+r>>1,Len=1;
		while(Len<(r-l+1<<1)+1)Len<<=1;BRT(Len);
		if(r-l+1<=50){
			h[ls].rsz(mid-l+1+1);
			F(i,0,mid-l+1){
				ULL s=0;
				F(j,0,r-l+1-i)s+=1ll*g[rs][j]*h[x][i+j]%mo;
				h[ls].val[i]=s%mo;
			}
			h[rs].rsz(r-mid+1);
			F(i,0,r-mid){
				ULL s=0;
				F(j,0,r-l+1-i)s+=1ll*g[ls][j]*h[x][i+j]%mo;
				h[rs].val[i]=s%mo;
			}
		}else{
			g[ls].Rev();g[rs].Rev();
			g[ls].rsz(Len);g[rs].rsz(Len);h[x].rsz(Len);
			g[ls].DFT();g[rs].DFT();h[x].DFT();
			F(i,0,Len-1)g[ls].val[i]=1ll*g[ls][i]*h[x][i]%mo;
			F(i,0,Len-1)g[rs].val[i]=1ll*g[rs][i]*h[x][i]%mo;
			g[ls].IDFT();g[rs].IDFT();
			h[ls].rsz(mid-l+1+1);
			F(i,0,mid-l+1)h[ls].val[i]=g[rs][i+r-mid];
			h[rs].rsz(r-mid+1);
			F(i,0,r-mid)h[rs].val[i]=g[ls][i+mid-l+1];
		}
		solve2(ls,l,mid);solve2(rs,mid+1,r);
	}
	void get(){
		int n=f.sz()-1,m=n+1;
		solve1(1,0,n);
		g[1]=g[1].inver(n+1);
		g[1].Rev();
		int Len=1;
		while(Len<(n<<1)+1)Len<<=1;BRT(Len);
		g[1].rsz(Len);f.rsz(Len);
		g[1].DFT();f.DFT();
		F(i,0,Len-1)g[1].val[i]=1ll*g[1][i]*f[i]%mo;
		g[1].IDFT();
		h[1].rsz(n+1);
		F(i,0,n)h[1].val[i]=g[1][i+n];
		solve2(1,0,n);
	}
}t;

poly f;

int n;

int main(){
	init();
	scanf("%d",&n);
	F(i,0,n-1){
		int x;
		scanf("%d",&x);
		f.ins(x);
	}
	t.f=f;
	t.get();
	F(i,0,n-1)f.val[i]=1ll*t.b[i]*ifac[i]%mo;
	poly g;
	F(i,0,n-1)g.ins((i&1)?mo-ifac[i]:ifac[i]);
	f*=g;
	F(i,0,n-1)printf("%d ",f[i]);
	return 0;
}

2.MTT

#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define mo 998244353
#define N 600010
#define LL long long
#define Ld long double

const Ld PI=acos(-1.0);

struct Complex{
	Ld real,img;
	Complex(Ld a=0.0,Ld b=0.0){real=a;img=b;}
	Complex Conj(){return Complex(real,-img);}
	friend Complex operator+(Complex a,Complex b){return Complex(a.real+b.real,a.img+b.img);}
	friend Complex operator-(Complex a,Complex b){return Complex(a.real-b.real,a.img-b.img);}
	friend Complex operator*(Complex a,Complex b){return Complex(a.real*b.real-a.img*b.img,a.real*b.img+a.img*b.real);}
	friend Complex operator*(Complex a,Ld b){return Complex(a.real*b,a.img*b);}
	friend Complex operator/(Complex a,Ld b){return Complex(a.real/b,a.img/b);}
	Complex operator+=(Complex x){return (*this)=(*this)+x;}
	Complex operator-=(Complex x){return (*this)=(*this)-x;}
	Complex operator*=(Complex x){return (*this)=(*this)*x;}
};

Complex G[N];

const Complex I=Complex(0,1);

int rev[N];

void BRT(int x){
	F(i,0,x-1)rev[i]=(rev[i>>1]>>1)|((i&1)?x>>1:0);
	F(i,0,x-1)G[i]=Complex(cos(2.0*PI/x*i),sin(2.0*PI/x*i));
}

void FFT(Complex *A,int Len,int x){
	F(i,0,Len-1)if(rev[i]<i)swap(A[rev[i]],A[i]);
	static Complex w[N];
	w[0]=Complex(1,0);
	for(int mid=1;mid<Len;mid<<=1){
		F(i,1,mid-1)w[i]=(x==1?G[i*(Len/(mid<<1))]:G[i*(Len/(mid<<1))].Conj());
		for(int i=0;i<Len;i+=mid<<1){
			Complex *omega=w;
			for(int j=0;j<mid;j++,omega++){
				Complex t=*omega*A[i|j|mid];
				A[i|j|mid]=A[i|j]-t;A[i|j]+=t;
			}
		}
	}
	if(x==-1){F(i,0,Len-1)A[i]=A[i]/(Ld)Len;}
}
void DFT(Complex *A,int Len){FFT(A,Len,1);}
void IDFT(Complex *A,int Len){FFT(A,Len,-1);}

void MTT(int*A,int*B,int*C,int l){
	vector<Complex>Pa(l),Pb(l),a0(l),a1(l),b0(l),b1(l);
	F(i,0,l-1){
		Pa[i]=Complex(A[i]>>15,A[i]&32767);
		Pb[i]=Complex(B[i]>>15,B[i]&32767);
	}
	DFT(Pa.data(),l);DFT(Pb.data(),l); 
	F(i,0,l-1){
		Complex Qa=(i?Pa[l-i].Conj():Pa[0].Conj()),Qb=(i?Pb[l-i].Conj():Pb[0].Conj());
		a0[i]=(Pa[i]+Qa)*0.5;a1[i]=(Qa-Pa[i])*0.5*I;
		b0[i]=(Pb[i]+Qb)*0.5;b1[i]=(Qb-Pb[i])*0.5*I;
	}
	F(i,0,l-1){
		Pa[i]=a0[i]*b0[i]+I*a1[i]*b0[i];
		Pb[i]=a0[i]*b1[i]+I*a1[i]*b1[i];
	}
	IDFT(Pa.data(),l);IDFT(Pb.data(),l);
	F(i,0,l-1){
		int na=(LL)(Pa[i].real+0.5)%mo,nb=(LL)(Pa[i].img+0.5)%mo,nc=(LL)(Pb[i].real+0.5)%mo,nd=(LL)(Pb[i].img+0.5)%mo;
		C[i]=(1ll*na*(1<<30)+1ll*(nb+nc)*(1<<15)+nd)%mo;
	}
}
int fac[N],ifac[N],inv[N];

int mod(int x){return x>=mo?x-mo:x;}

int mi(int x,int y){
	if(!y)return 1;
	if(y==1)return x;
	return y%2?1ll*x*mi(1ll*x*x%mo,y/2)%mo:mi(1ll*x*x%mo,y/2);
}

void init(){
	fac[0]=ifac[0]=1;
	F(i,1,N-10)fac[i]=1ll*fac[i-1]*i%mo,inv[i]=(i==1?1:1ll*mo/i*mod(mo-1ll*inv[mo%i]%mo)%mo);
	ifac[N-10]=mi(fac[N-10],mo-2);
	Fd(i,N-11,1)ifac[i]=1ll*ifac[i+1]*(i+1)%mo;
}

struct poly_NTT{
	vector<int>val;
	poly_NTT(int x=0){if(x)val.push_back(x);}
	poly_NTT(const vector<int>&x){val=x;}
	void Rev(){reverse(val.begin(),val.end());}
	void ins(int x){val.push_back(x);}
	void clear(){vector<int>().swap(val);}
	int sz(){return val.size();}
	void rsz(int x){val.resize(x);}
	void shrink(){for(;sz()&&!val.back();val.pop_back());}
	poly_NTT modxn(int x){
		if(val.size()<=x)return poly_NTT(val);
		else return poly_NTT(vector<int>(val.begin(),val.begin()+x));
	}
	int operator[](int x)const{
		if(x<0||x>=val.size())return 0;
		return val[x];
	}
	friend poly_NTT operator*(poly_NTT x,poly_NTT y){
		if(x.sz()<30||y.sz()<30){
			if(x.sz()>y.sz())swap(x,y);
			poly_NTT ret;
			ret.rsz(x.sz()+y.sz());
			F(i,0,ret.sz()-1){
				for(int j=0;j<=i&&j<x.sz();j++)
					ret.val[i]=mod(ret.val[i]+1ll*x[j]*y[i-j]%mo);
			}
	//		ret.shrink();
			return ret;
		}
		int l=1;
		while(l<x.sz()+y.sz()-1)l<<=1;
		x.rsz(l);BRT(l);
		static int A[N],B[N],C[N];
		F(i,0,x.sz()-1)A[i]=x[i];F(i,x.sz(),l-1)A[i]=0;
		F(i,0,y.sz()-1)B[i]=y[i];F(i,y.sz(),l-1)B[i]=0;
		MTT(A,B,C,l);
		F(i,0,l-1)x.val[i]=C[i];
//		x.shrink();
		return x;
	}
	friend poly_NTT operator+(poly_NTT x,poly_NTT y){
		poly_NTT ret;
		ret.rsz(max(x.sz(),y.sz()));
		F(i,0,ret.sz()-1)ret.val[i]=mod(x[i]+y[i]);
		return ret;
	}
	friend poly_NTT operator-(poly_NTT x,poly_NTT y){
		poly_NTT ret;
		ret.rsz(max(x.sz(),y.sz()));
		F(i,0,ret.sz()-1)ret.val[i]=mod(x[i]-y[i]+mo);
		return ret;
	}
	poly_NTT &operator*=(poly_NTT x){return (*this)=(*this)*x;}
	poly_NTT &operator+=(poly_NTT x){return (*this)=(*this)+x;}
	poly_NTT &operator-=(poly_NTT x){return (*this)=(*this)-x;}
	poly_NTT deriv(){
		poly_NTT f;
		f.rsz(sz()-1);
		F(i,0,sz()-2)f.val[i]=1ll*(i+1)*val[i+1]%mo;
		return f;
	}
	poly_NTT integ(){
		poly_NTT f;
		f.rsz(sz()+1);
		F(i,1,sz())f.val[i]=1ll*val[i-1]*inv[i]%mo;
		return f;
	}
	poly_NTT inver(int Len){
		poly_NTT res(mi(val[0],mo-2));
		for(int i=1;i<Len;){
			i<<=1;
			res=(res*(2-res*modxn(i))).modxn(i);
		}
		return res.modxn(Len);
	}
	poly_NTT Sqrt(int Len){
		poly_NTT f,res(1);
		for(int i=1;i<Len;){
			i<<=1;
			f=res.inver(i);
			res=((res+f*modxn(i))*inv[2]).modxn(i);
		}
		return res.modxn(Len);
	}
	poly_NTT Ln(int Len){
		return (deriv()*inver(Len)).integ().modxn(Len);
	}
	poly_NTT Exp(int Len){
		poly_NTT f(1);
		for(int i=2;i<Len*2;i<<=1)f=(f*(1-f.Ln(i)+modxn(i))).modxn(i);
		return f.modxn(Len);
	}
	poly_NTT Pow(int Len,int k){
		poly_NTT f;
		f.clear();
		int tail=0;
		while(val[tail]==0&&tail<sz())tail++;
		if(tail>=sz())return f;
		if(tail*k>=Len)return f;
		f.rsz(Len);
		int Mul=mi(val[tail],mo-2);
		F(i,0,min(Len-1,sz()-tail-1))f.val[i]=1ll*val[i+tail]*Mul%mo;
		Mul=mi(val[tail],k);
		f=f.Ln(Len);
		F(i,0,Len-1)f.val[i]=1ll*f[i]*(k%mo)%mo;
		f=f.Exp(Len);
		Fd(i,Len-1,tail*k)f.val[i]=1ll*f[i-tail*k]*Mul%mo;
		F(i,0,tail*k-1)f.val[i]=0;
		return f;
	}
};

int main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	init();
	return 0;
}
posted @ 2022-01-06 19:03  冰雾  阅读(52)  评论(0编辑  收藏  举报