1. 程式人生 > 實用技巧 >多項式全家桶

多項式全家桶

#include<bits/stdc++.h>
using namespace std;
const int mod=998244353,G=3,ivG=332748118,N=4e6+5;
inline int in()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*f;
} 
struct poly
{
	vector<int>v;
	inline int&operator[](int x)
	{
		while(x>=v.size())v.push_back(0);
		return v[x];
	}
	inline void pre(int x,int lim)
	{
		int t=min(lim,(int)v.size());
		for(int i=x;i<t;++i)v[i]=0;
	}
};
namespace Math
{
	int inv[N],pif;
	inline int add(int x,int y){x+=y;return x>=mod?x-mod:x;}
	inline int dec(int x,int y){x-=y;return x<0?x+mod:x;}
	inline int mll(int x,int y){return 1ll*x*y%mod;}
	struct pt
	{
		int x,y;
		pt(int _x=0,int _y=0){x=_x,y=_y;}
		inline pt operator*(const pt&rhs)
		{
			return pt(add(mll(x,rhs.x),mll(mll(y,rhs.y),pif)),add(mll(x,rhs.y),mll(y,rhs.x)));
		}
	};
	inline int qpow(int x,int y)
	{
		int ans=1;
		for(;y;y>>=1,x=mll(x,x))(y&1)&&(ans=mll(ans,x));
		return ans;
	}
	inline pt qpow(pt x,int y)
	{
		pt ans=pt(1,0);
		for(;y;y>>=1,x=x*x)if(y&1)ans=ans*x;
		return ans;
	}
	inline void pre(int n)
	{
		inv[1]=1;
		for(int i=2;i<=n;++i)inv[i]=mod-mll(mod/i,inv[mod%i]);
	}
	inline bool ck(int x){return qpow(x,(mod-1)>>1)==mod-1;}
	inline int solve(int x)
	{
		int ans=0;
		if(mod==2)return x;
		if(!x)return 0;
		else if(qpow(x,(mod-1)>>1)==mod-1)return -1;
		int a=rand()%mod;
		while(!a||!ck(dec(mll(a,a),x)))a=rand()%mod;
		pif=dec(mll(a,a),x);
		ans=qpow(pt(a,1),(mod+1)>>1).x;
		return min(ans,mod-ans);
	}
}
using namespace Math;
namespace Bas
{
	int rev[N],wn[N];
	inline void ntt(int lim,poly&f,bool tp)
	{
		for(int i=0;i<lim;++i)if(i<rev[i])swap(f[i],f[rev[i]]);
		for(int mid=1;mid<lim;mid<<=1)
		{
			int sw=qpow(tp?ivG:G,(mod-1)/(mid<<1));
			wn[0]=1;for(int i=1;i<mid;++i)wn[i]=mll(wn[i-1],sw);
			for(int len=mid<<1,p=0;p+len-1<lim;p+=len)
				for(int k=0;k<mid;++k)
				{
					int x=f[p+k],y=1ll*wn[k]*f[p+mid+k]%mod;
					f[p+k]=add(x,y),f[p+mid+k]=dec(x,y);
				}
		}
	}
	inline poly mul(int n,int m,poly f,poly g)
	{
		int lim=1,l=0;while(lim<n+m)lim<<=1,++l;
		for(int i=0;i<lim;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
		f.pre(n,lim),g.pre(m,lim);
		ntt(lim,f,0),ntt(lim,g,0);
		for(int i=0;i<lim;++i)f[i]=mll(f[i],g[i]);
		ntt(lim,f,1);int iv=qpow(lim,mod-2);
		for(int i=0;i<lim;++i)f[i]=mll(f[i],iv);
		return f;
	}
	inline void igl(int n,poly&f)
	{
		for(int i=n-1;i;--i)f[i]=mll(f[i-1],inv[i]);f[0]=0;
	}
	inline void diff(int n,poly&f)
	{
		for(int i=0;i<n-1;++i)f[i]=mll(f[i+1],i+1);f[n-1]=0;
	}
	inline void rv(int n,poly&f){reverse(f.v.begin(),f.v.begin()+n);}
	inline void read(int n,poly&f){for(int i=0;i<n;++i)f[i]=in();}
	inline void print(int n,poly f){for(int i=0;i<n;++i)printf("%d ",f[i]);puts("");}
}
using namespace Bas;
namespace Poly
{
	poly ginv(int n,poly f)
	{
		if(n==1){poly g;g[0]=qpow(f[0],mod-2);return g;}
		poly g=ginv(n+1>>1,f),h,p=g;
		int lim=1,l=0;while(lim<n+n)lim<<=1,++l;
		for(int i=0;i<lim;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
		f.pre(n,lim),p.pre(n,lim);
		ntt(lim,f,0),ntt(lim,p,0);
		for(int i=0;i<lim;++i)f[i]=mll(f[i],mll(p[i],p[i]));
		ntt(lim,f,1);int iv=qpow(lim,mod-2);
		for(int i=0;i<n;++i)h[i]=dec(add(g[i],g[i]),mll(f[i],iv));
		return h;
	}
	inline poly ln(int n,poly f)
	{
		poly g=ginv(n,f),h;diff(n,f);
		h=mul(n,n,f,g);igl(n,h);
		return h;
	}
	poly exp(int n,poly f)
	{
		if(n==1){poly g;g[0]=1;return g;}
		poly g=exp(n+1>>1,f);
		poly h=ln(n,g);
		for(int i=0;i<n;++i)h[i]=add(dec(0,h[i]),f[i]);
                h[0]=add(h[0],1);
		return mul(n,n,g,h);
	}
	inline poly div(int n,int m,poly f,poly g)
	{
		rv(n,f),rv(m,g);
		g=ginv(n-m+1,g);
		poly q=mul(n,n-m+1,f,g);
		rv(n-m+1,q);return q;
	}
	inline poly sqr(int n,poly f)
	{
		if(n==1){poly g;g[0]=solve(f[0]);return g;}
		poly g=sqr(n+1>>1,f),h,ivg;
		ivg=ginv(n,g),h=mul(n,n,g,g);
		int iv=qpow(2,mod-2);
		for(int i=0;i<n;++i)ivg[i]=mll(iv,ivg[i]);
		for(int i=0;i<n;++i)h[i]=dec(h[i],f[i]);
		h=mul(n,n,h,ivg);
		for(int i=0;i<n;++i)h[i]=dec(g[i],h[i]);
		return h;
	}
	inline poly fsp(int n,int k1,int k2,poly f)
	{
		int u,k;poly ans;
		for(u=0;u<n&&!f[u];++u);k=qpow(f[u],k2);
		if(1ll*u*k2>=n)return ans;
		int iv=qpow(f[u],mod-2);
		for(int i=u;i<n;++i)f[i]=mll(f[i],iv);
		for(int i=0,j=u;j<n;++i,++j)ans[i]=f[j];
		ans=ln(n,ans);
		for(int i=0;i<n;++i)ans[i]=mll(ans[i],k1);
		ans=exp(n,ans);
		for(int i=0;i<u*k2;++i)f[i]=0;
		for(int i=u*k2,j=0;i<n;++i,++j)f[i]=mll(ans[j],k);
		return f;
	}
}
using namespace Poly;
char ch[N];
int main()
{
	int n,k1=0,k2=0,k3=0;scanf("%d",&n);pre(n);
	scanf("%s",ch+1);int len=strlen(ch+1);
	poly f;read(n,f);
	for(int i=1;i<=len;++i)
	{
		k1=add(mll(10,k1),ch[i]^48),
		k2=(10ll*k2%(mod-1)+(ch[i]^48))%(mod-1);
		if(k1>n&&!f[0])
		{
			for(int i=0;i<n;++i)printf("0 ");
			return 0;
		}
	}
	print(n,fsp(n,k1,k2,f));//主函式對應的是多項式快速冪加強版:即不保證a0=1
	return 0;
}