Polynomial

静态数组版本

#include<bits/stdc++.h>

using namespace std;

const int mo=998244353;
const int maxn=1<<20;

int add(int x,int y){
	return (x+y>=mo)?x+y-mo:x+y;
}

int sub(int x,int y){
	return (x-y<0)?x-y+mo:x-y;
}

int mul(int x,int y){
	return 1ll*x*y%mo;
}

#define gc getchar
int rd(){
	int f=1,r=0;
	char ch=gc();
	while(!isdigit(ch)){ if(ch=='-') f=-1;ch=gc();}
	while(isdigit(ch)){ r=(r<<1)+(r<<3)+(ch^48);ch=gc();}
	return f*r;
}

int ksm(int x,int y){
	int rs=1;
	while(y){
		if(y&1) rs=1ll*rs*x%mo;
		x=1ll*x*x%mo;
		y>>=1;
	}
	return rs;
}

int rev[maxn];	

void init_rev(int len){
	for(int i=0;i<len;++i){
		rev[i]=rev[i>>1]>>1;
		if(i&1) rev[i]|=len>>1;
	}
}

namespace Polynomial{
	struct poly{
		int a[maxn];
		
		poly(){memset(a,0,sizeof(a));};
		
		int& operator[](int x){
			return a[x];
		}
		
		int operator[](int x)const{
			return a[x];
		}
		
		void operator=(const poly &t){
			memcpy(a,t.a,sizeof(a));
			return;
		}
		
		void slice(int len,int k){
			for(int i=len;i<k;++i) a[i]=0;
		}
		
		void NTT(int len,int rv){
			for(int i=0;i<len;++i) if(i<rev[i]) swap(a[i],a[rev[i]]);
			for(int h=2;h<=len;h<<=1){
				int wn=ksm(3,(mo-1)/h);
				for(int i=0;i<len;i+=h){
					int w=1;
					for(int k=i;k<i+h/2;++k){
						int u=a[k],v=mul(w,a[k+h/2]);
						a[k]=add(u,v);
						a[k+h/2]=sub(u,v);
						w=mul(w,wn);
					}
				}
			}
			if(rv==-1){
				reverse(a+1,a+len);
				int inv=ksm(len,mo-2);
				for(int i=0;i<len;++i) a[i]=mul(a[i],inv);
			}
		}
		
		poly inv(int len)const{
			poly g,g0,d;
			g[0]=ksm(a[0],mo-2);
			for(int lim=2;(lim>>1)<len;lim<<=1){
				g0=g,d=*this;
				d.slice(lim,len);
				int k=lim<<1;
				init_rev(k);
				g0.NTT(k,1),d.NTT(k,1);
				for(int i=0;i<k;++i) g0[i]=mul(g0[i],sub(2,mul(g0[i],d[i])));
				g0.NTT(k,-1);
				g0.slice(lim,k);
				g=g0;
			}
			return g;
		}
		
		poly der(int len)const{
			poly g=*this;
			for(int i=0;i<len;++i) g[i]=mul(g[i+1],i+1);
			return g;
		}
		
		poly integ(int len)const{
			poly g=*this;
			for(int i=len-1;i;--i) g[i]=mul(g[i-1],ksm(i,mo-2));
			g[0]=0;
			return g;
		}
		
		poly ln(int len)const{
			poly d=this->der(len),iv=this->inv(len),rs;
			int k=len<<1;
			init_rev(k);
			d.NTT(k,1),iv.NTT(k,1);
			for(int i=0;i<k;++i) rs[i]=mul(d[i],iv[i]);
			rs.NTT(k,-1);
			rs=rs.integ(k);
			rs.slice(len,k);
			return rs;
		}
		
		poly Exp(int len)const{
			poly g,g0,lng,d;
			g[0]=1;
			int k;
			for(int lim=2;(lim>>1)<len;lim<<=1){
				k=lim<<1;
				g0=g,lng=g.ln(k),d=*this;
				d.slice(lim,k);
				lng.slice(lim,k);
				init_rev(k);
				g0.NTT(k,1),lng.NTT(k,1),d.NTT(k,1);
				for(int i=0;i<k;++i) g[i]=mul(g0[i],add(sub(1,lng[i]),d[i]));
				g.NTT(k,-1);
				g.slice(lim,k);
			}
			g.slice(len,k);
			return g;
		}
		
		poly Mul(int len,int k)const{
			poly rs=*this;
			for(int i=0;i<len;++i) rs[i]=mul(rs[i],k);
			return rs;
		}
		
		poly pow(int len,int k)const{
			poly rs=this->ln(len);
			rs=rs.Mul(len,k);
			rs=rs.Exp(len);
			return rs;
		}
		
		poly rv(int len)const{
			poly rs=*this;
			reverse(rs.a,rs.a+len);
			return rs;
		}
		
		pair<poly,poly> modulo(int n,int m,const poly g)const{
			poly rf=this->rv(n+1),rg=g.rv(m+1),q,r;
			rf.slice(n-m+1,n+1),rg.slice(n-m+1,m+1);
			int k=1;
			while(k<=(n-m+1)) k<<=1;
			rg=rg.inv(k);
			while(k<=(n-m+1)*2) k<<=1;
			init_rev(k);
			rf.NTT(k,1),rg.NTT(k,1);
			for(int i=0;i<k;++i) q[i]=mul(rf[i],rg[i]);
			q.NTT(k,-1);
			q.slice(n-m+1,k);
			q=q.rv(n-m+1);
			poly f=*this,G=g;
			k=1;
			while(k<=2*max(n+1,m+1)) k<<=1;
			init_rev(k);
			f.NTT(k,1),G.NTT(k,1),q.NTT(k,1);
			for(int i=0;i<k;++i) r[i]=sub(f[i],mul(q[i],G[i]));
			r.NTT(k,-1),q.NTT(k,-1);
			q.slice(n-m+1,k);
			r.slice(m,k);
			return make_pair(q,r);
		}
	};
}
using namespace Polynomial;

vector 版本

#include<bits/stdc++.h>

using namespace std;

using i64=long long;

constexpr int mo=998244353,maxn=1<<21;

int n;

inline int add(int x,int y){
	x+=y;return x<mo?x:x-mo;
}

inline void upd(int &x,int y){
	x=add(x,y);return;
}

int ksm(int x,int y){
	int rs=1;for(;y;y>>=1,x=(i64)x*x%mo) if(y&1) rs=(i64)rs*x%mo;return rs;
}

int inv[maxn];

void initinv(){
	inv[1]=1;for(int i=2;i<maxn;++i) inv[i]=(i64)(mo-mo/i)*inv[mo%i]%mo;
}

int rev[maxn];

inline int getmi(int n){
	int len=1;while(len<n) len<<=1;	
	return len;
}

int initrev(int n){
	int len=getmi(n);
	for(int i=1;i<len;++i){
		rev[i]=rev[i>>1]>>1;
		if(i&1) rev[i]|=len>>1;
	}
	return len;
}

struct Poly{
	vector<int> v;
	int L;
	
	Poly(){vector<int>().swap(v);L=0;}
	
	int& operator[](int x){
		return v[x];
	}
	
	void slice(int len){ v.resize(len);L=len;}
	
	void NTT(int len,bool typ){
		for(int i=1;i<len;++i) if(i<rev[i]) swap(v[i],v[rev[i]]);
		for(int h=2;h<=len;h<<=1){
			int w=ksm(3,(mo-1)/h);
			for(int i=0;i<len;i+=h){
				int wn=1;
				for(int j=i;j<i+h/2;++j){
					int x=v[j],y=(i64)wn*v[j+h/2]%mo;
					v[j]=add(x,y);v[j+h/2]=add(x,mo-y);
					wn=(i64)wn*w%mo;
				}
			}
		}
		
		if(!typ){
			reverse(v.begin()+1,v.end());
			for(int i=0;i<len;++i) v[i]=(i64)v[i]*inv[len]%mo;
		}
	}
	
	Poly operator*(const Poly &F){
		Poly rs,f,g;f=*this;g=F;
		
		int len=initrev(L+F.L-1);
		f.slice(len);g.slice(len);rs.slice(len);
		
		f.NTT(len,1);g.NTT(len,1);
		for(int i=0;i<len;++i) rs.v[i]=(i64)f.v[i]*g.v[i]%mo;
		rs.NTT(len,0);
		
		return rs;
	}
	
	Poly Inv(){
		Poly g,g0,f;
		int Lim=getmi(L);
		g.slice(1);g[0]=ksm(v[0],mo-2);
		for(int len=2;(len>>1)<Lim;len<<=1){
			f=*this;f.slice(len);
			
			len<<=1;
			f.slice(len);g.slice(len);g0=g;
			initrev(len);
			
			g0.NTT(len,1);f.NTT(len,1);
			for(int i=0;i<len;++i) g[i]=(i64)g0[i]*add(2,mo-(i64)f[i]*g0[i]%mo)%mo;
			g.NTT(len,0);
			
			len>>=1;
			g.slice(len);
		}
		g.slice(L);
		return g;
	}
	
	Poly Der(){
		Poly rs;rs.slice(L-1);
		for(int i=1;i<=L-1;++i) rs[i-1]=(i64)v[i]*i%mo;
		return rs;
	}
	
	Poly Int(){
		Poly rs;rs.slice(L+1);rs[0]=0;
		for(int i=1;i<=L;++i) rs[i]=(i64)v[i-1]*inv[i]%mo;
		return rs;
	}
	
	Poly Ln(){
		Poly rs=(this->Der())*(this->Inv());
		rs=rs.Int();rs.slice(L);
		return rs;
	}
	
	Poly Exp(){
		Poly f,g,g0,gln;
		int Lim=getmi(L);
		g.slice(1);g[0]=1;
		for(int len=2;(len>>1)<Lim;len<<=1){
			f=*this;f.slice(len);
			g.slice(len);gln=g.Ln();gln.slice(len);
			
			len<<=1;
			f.slice(len);gln.slice(len);g.slice(len);g0=g;
			
			initrev(len);
			g0.NTT(len,1);f.NTT(len,1);gln.NTT(len,1);
			for(int i=0;i<len;++i) g[i]=(i64)g0[i]*add(1,add(mo-gln[i],f[i]))%mo;
			g.NTT(len,0);
			
			len>>=1;
			g.slice(len);
		}
		g.slice(L);
		return g;
	}
}F,ans;

int main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	
	initinv();
	
	cin>>n;
	F.slice(n);
	for(int i=0;i<n;++i) cin>>F[i];
	
	ans=F.Exp();
	for(int i=0;i<n;++i) cout<<ans[i]<<' ';cout<<'\n';
	
	return 0;
}
posted @ 2025-02-11 20:09  RandomShuffle  阅读(28)  评论(0)    收藏  举报