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;
posted @   RandomShuffle  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示