多项式全家桶

放个板子

#define ll long long
#define cri const register int
#define re register
#define int ll
#define cp const cplx
using namespace std;
#define vcp vector<cplx>
#define vdb vector<double>
#define vnt vector<int>
#define cp const cplx
#define rs(x) x.resize(bin) 
#define P 3.141592653589793L
const int lim=(1<<15);
const int mod=998244353;
inline void db(vnt &a,cri bin){
	for(int i=0;i<bin;i++) cout<<a[i]<<" "; puts("");
}
inline ll qpow(ll a,ll b,ll ans=1){
	for(;b;b>>=1,a=a*a%mod) if(b&1) ans=ans*a%mod;
	return ans;
}
inline void rnt(vnt &A,cri bin){
	rs(A);
	for(int i=0;i<bin;i++) A[i]=0;
}
inline int r(double x){
	return (int)(x+0.5);
}
inline int mo(cri x){
	return x>=mod?x-mod:x;
}
struct cplx{
	double rl,ig;
	cplx(double r=0,double i=0){ this->rl=r;this->ig=i; }
	friend cplx operator + (const cplx &a,const cplx &b){
		return cplx(a.rl+b.rl,a.ig+b.ig);
	}
	friend cplx operator - (const cplx &a,const cplx &b){
		return cplx(a.rl-b.rl,a.ig-b.ig);
	}
	friend cplx operator * (const cplx &a,const cplx &b){
		return cplx(a.rl*b.rl-a.ig*b.ig,a.rl*b.ig+b.rl*a.ig);
	}
};
vcp ww[19];
inline void put(vnt &A,cri bin){
	for(int i=0;i<bin;i++) printf("%d ",A[i]);puts("");
}
struct node{
	vnt pd[250010];
	inline void clear(vnt &A,cri len,cri bin){ for(int i=len;i<bin;i++) A[i]=0; }
	inline void ntt(vnt &A,cri bin,cri opt){
		vnt v;rnt(v,bin);
		for(int i=0;i<bin;i++) v[i]=v[i>>1]>>1|(i&1?bin>>1:0);//,cout<<v[i]<<" ";puts("");
		for(int i=0;i<bin;i++) if(i<v[i]) swap(A[i],A[v[i]]);
		for(int i=1;i<bin;i<<=1){
			const ll wn=qpow(3,opt*(mod-1)/(i<<1)+mod-1);
			for(int j=0,w=1;j<bin;j+=(i<<1),w=1)
				for(int k=0;k<i;k++,w=w*wn%mod) {
					ll x=A[j+k],y=w*A[j+k+i]%mod;
					A[j+k]=mo(x+y);A[j+k+i]=mo(x-y+mod);
				}
		}
		if(opt==-1) for(int i=0,pw=qpow(bin,mod-2);i<bin;i++) A[i]=A[i]*pw%mod;
	}
	inline void fft(vcp &A,cri bin,cri opt){
		vnt v;rnt(v,bin);
		for(int i=0;i<bin;i++) v[i]=v[i>>1]>>1|(i&1?bin>>1:0);
		for(int i=0;i<bin;i++) if(i<v[i]) swap(A[i],A[v[i]]);
		for(int i=1,g=0;i<bin;i<<=1,g++)
			for(int j=0;j<bin;j+=(i<<1))
				for(int k=0;k<i;k++){
					cp x=A[j+k],y=ww[g][k]*A[j+k+i];
					A[j+k]=x+y;A[j+k+i]=x-y;
				}
		if(opt==1) return;
		reverse(A.begin()+1,A.begin()+bin);
		for(int i=0;i<bin;i++) A[i].rl/=bin;
	}
	inline void mul(vnt &A,vnt &B,cri bin,cri opt){
		if(!opt){	
			ntt(A,bin,1);ntt(B,bin,1);
			for(int i=0;i<bin;i++) A[i]=A[i]*B[i]%mod;
			ntt(A,bin,-1);ntt(B,bin,-1);
		}
		else {
			vcp p1,p2,p3,p4;rs(p1);rs(p2);rs(p3);rs(p4);
			for(int i=0;i<bin;i++)
				p1[i]=cplx(A[i]>>15,0),p2[i]=cplx(A[i]&(lim-1),0),
				p3[i]=cplx(B[i]>>15,0),p4[i]=cplx(B[i]&(lim-1),0);
			fft(p2,bin,1);fft(p4,bin,1);fft(p3,bin,1);fft(p1,bin,1);
			for(int i=0;i<bin;i++){
				const cplx a=p1[i],b=p2[i],c=p3[i],d=p4[i];
				p1[i]=a*c;p2[i]=(b*c)+(a*d);p3[i]=d*b;
			}
			fft(p3,bin,-1);fft(p1,bin,-1);fft(p2,bin,-1);
			for(int i=0;i<bin;i++)
				A[i]=(r(p1[i].rl)%mod*lim%mod*lim%mod+r(p2[i].rl)%mod*lim%mod+r(p3[i].rl))%mod;
		}
	}
	void inv(vnt &A,vnt &B,cri len,cri opt){
		if(len==1) return B[0]=qpow(A[0],mod-2),void();
		inv(A,B,len+1>>1,opt);
		int bin=1;
		while(bin<len+len) bin<<=1;
		vnt t1,t2;rnt(t1,bin);rnt(t2,bin);
		for(int i=0;i<len;i++) t1[i]=A[i],t2[i]=B[i];
		clear(B,len,bin);
		mul(t1,t2,bin,opt); 
		clear(t1,len,bin);
		mul(t1,t2,bin,opt);
		for(int i=0;i<len;i++) B[i]=(B[i]*2-t1[i]+mod)%mod;
	}
	void sqrt(vnt &A,vnt &B,cri len,cri opt){
		if(len==1) return B[0]=1,void();
		sqrt(A,B,len+1>>1,opt);
		int bin=1;
		while(bin<len+len) bin<<=1;
		vnt t3,t4,tmp;rnt(t3,bin);rnt(t4,bin);rnt(tmp,bin);
		for(int i=0;i<len;i++) t3[i]=A[i],t4[i]=B[i];
		clear(B,len,bin);
		inv(t4,tmp,len,opt);
		mul(t3,tmp,bin,opt);
		for(int i=0,p=qpow(2,mod-2);i<len;i++) B[i]=(t3[i]+B[i])*p%mod;
	}
	inline void dao(vnt &A,vnt &B,cri bin){ 
		for(int i=1;i<bin;i++) B[i-1]=A[i]*i%mod;B[bin-1]=0; 
	}
	inline void jifen(vnt &A,vnt &B,cri bin){
		for(int i=1;i<bin-1;i++) B[i]=A[i-1]*qpow(i,mod-2)%mod;B[0]=0;
	}
	inline void ln(vnt &A,vnt &B,cri len,cri opt,int bin=1){
		while(bin<len+len) bin<<=1;
		vnt t5,t6;rnt(t5,bin);rnt(t6,bin);
		inv(A,t5,len,opt);
		dao(A,t6,bin);
		mul(t5,t6,bin,opt);
		jifen(t5,B,bin);
	}
	void exp(vnt &A,vnt &B,cri len,cri opt,int bin=1){
		if(len==1) return B[0]=1,void();
		exp(A,B,len+1>>1,opt);
		while(bin<len+len) bin<<=1;
		vnt t7;rnt(t7,bin);
		clear(B,len,bin);
		ln(B,t7,len,opt);
		for(int i=0;i<len;i++) t7[i]=mo(A[i]-t7[i]+mod);t7[0]++;
		mul(B,t7,bin,opt);clear(B,len,bin);
	}
	void prod(cri k,vnt &A,cri l,cri r,cri n,cri opt,int bin=1){
		while(bin<=n) bin<<=1;rnt(pd[k],bin<<1);
		if(l==r) return pd[k][0]=mod-A[l],pd[k][1]=1,void();
		cri mid=l+r>>1,L=k<<1,R=L|1;;
		prod(L,A,l,mid,mid-l+1,opt);prod(R,A,mid+1,r,r-mid,opt);
		ntt(pd[L],bin,1);ntt(pd[R],bin,1);
		for(int i=0;i<bin;i++) pd[k][i]=pd[L][i]*pd[R][i]%mod;
		ntt(pd[L],bin,-1);ntt(pd[R],bin,-1);ntt(pd[k],bin,-1);
	}
	void div(vnt &F,vnt &G,vnt &PP,vnt &Q,cri n,cri m,cri opt){
		if(n<m) return Q=F,void();
		vnt G0=G,invG;int bin=1,M=min(m+1,n-m+1);
		while(bin<M+M) bin<<=1;
		rnt(invG,bin);
		for(int i=0;i<M;i++) PP[i]=F[n-i];
		reverse(G0.begin(),G0.begin()+m+1);//put(G0,bin);
		inv(G0,invG,M,opt);
		mul(PP,invG,bin,opt);
		reverse(PP.begin(),PP.begin()+M);clear(PP,M,bin);
		Q=G;mul(Q,PP,Q.size(),opt);
		for(int i=0;i<m;i++) Q[i]=mo(F[i]-Q[i]+mod);
	}
	void solve(cri k,vnt &A,vnt &ANS,cri l,cri r,cri n,cri opt){
		if(l==r){ ANS[l]=A[0];return; }
		int mid=l+r>>1,L=k<<1,R=L|1,bin=1;
		while(bin<=n+n) bin<<=1;
		vnt q1,q2;
		
		rnt(q1,bin);rnt(q2,bin);
		div(A,pd[L],q1,q2,n,mid-l+1,opt);
		solve(L,q2,ANS,l,mid,mid-l,opt);
		
		rnt(q1,bin);rnt(q2,bin);
		div(A,pd[R],q1,q2,n,r-mid,opt);
		solve(R,q2,ANS,mid+1,r,r-mid-1,opt);
	}
	void fst_get(vnt &A,vnt &ND,vnt &ANS,cri n,cri m,cri opt,int bin=1){
		prod(1,ND,1,m,m,0);
		solve(1,A,ANS,1,m,n,0);
	}
}ntt;
signed main(){
}
posted @ 2019-12-20 15:48  mikufun♘  阅读(104)  评论(0编辑  收藏  举报