多项式模板--zhengjun

vector 实现。

using LL=__int128;
const int mod=998244353;
ll qpow(ll x,ll y=mod-2,ll ans=1){
	for(;y;(x*=x)%=mod,y>>=1)if(y&1)(ans*=x)%=mod;
	return ans;
}
mt19937 rnd(time(0));
int sqr(int n){
	int a,val;
	auto chk=[&](int x){
		return qpow(x,(mod-1)/2)==1;
	};
	do a=rnd()%mod;while(chk(val=(1ll*a*a-n)%mod));
	struct comp{
		int x,y;
		comp(int a=0,int b=0):x(a),y(b){}
		comp operator + (const comp &a)const{
			return comp((x+a.x)%mod,(y+a.y)%mod);
		}
	}x(a,1),ans(1,0);
	auto mul=[&](comp a,comp b){
		return comp((1ll*a.x*b.x+1ll*a.y*b.y%mod*val)%mod,(1ll*a.x*b.y+1ll*a.y*b.x)%mod);
	};
	int y=(mod+1)/2;
	for(;y;x=mul(x,x),y>>=1)if(y&1)ans=mul(ans,x);
	return min(ans.x,mod-ans.x);
}
namespace Poly{
	const int N=1<<21,g=3;
	int lim,rev[N],A[N],B[N],pw[N];
	void init(int n){
		for(lim=1;lim<n;lim<<=1);
		for(int i=1;i<lim;i++)rev[i]=rev[i>>1]>>1|(i&1?lim>>1:0);
	}
	void Init(){
		int x=qpow(g,(mod-1)/N);
		pw[N/2]=1;
		for(int i=N/2+1;i<N;i++)pw[i]=1ll*pw[i-1]*x%mod;
		for(int i=N/2-1;i;i--)pw[i]=pw[i<<1];
	}
	namespace Public{
		using poly=vector<int>;
		void NTT(int *f,int op){
			static unsigned long long a[N];
			for(int i=0;i<lim;i++)a[i]=f[rev[i]];
			for(int len=1,x;len<lim;len<<=1){
				for(int i=0;i<lim;i+=len<<1){
					for(int j=0;j<len;j++){
						x=a[i|j|len]*pw[len|j]%mod;
						a[i|j|len]=a[i|j]+mod-x,a[i|j]+=x;
					}
				}
				if(len>>16&1){
					for(int i=0;i<lim;i++)a[i]%=mod;
				}
			}
			for(int i=0;i<lim;i++)f[i]=a[i]%mod;
			if(op<0){
				reverse(f+1,f+lim);
				int x=qpow(lim);
				for(int i=0;i<lim;i++)f[i]=1ll*f[i]*x%mod;
			}
		}
		poly operator * (const poly &a,const poly &b){
			int n=a.size(),m=b.size(),k=n+m-1;
			init(k);
			copy(a.begin(),a.end(),A),fill(A+n,A+lim,0);
			copy(b.begin(),b.end(),B),fill(B+m,B+lim,0);
			poly c(k);
			NTT(A,1),NTT(B,1);
			for(int i=0;i<lim;i++)A[i]=1ll*A[i]*B[i]%mod;
			NTT(A,-1);
			for(int i=0;i<k;i++)c[i]=A[i];
			return c;
		}
		poly& operator *= (poly &a,const poly &b){
			return a=a*b;
		}
		poly& operator += (poly &a,const poly &b){
			int n=a.size(),m=b.size();
			if(n<m)a.resize(m);
			for(int i=0;i<m;i++)(a[i]+=b[i])%=mod;
			return a;
		}
		poly operator + (const poly &a,const poly &b){
			poly c(a);
			return c+=b;
		}
		poly& operator -= (poly &a,const poly &b){
			int n=a.size(),m=b.size();
			if(n<m)a.resize(m);
			for(int i=0;i<m;i++)(a[i]+=mod-b[i])%=mod;
			return a;
		}
		poly operator - (const poly &a,const poly &b){
			poly c(a);
			return c-=b;
		}
		poly operator - (const poly &a){
			return poly()-a;
		}
		poly& operator *= (poly &a,const int &b){
			for(int &x:a)x=1ll*x*b%mod;
			return a;
		}
		poly operator * (const poly &a,const int &b){
			poly c(a);
			return c*=b;
		}
		poly& operator /= (poly &a,const int &b){
			return a*=qpow(b);
		}
		poly operator / (const poly &a,const int &b){
			poly c(a);
			return c/=b;
		}
		poly& operator %= (poly &a,const int &b){
			if(a.size()>b)a.resize(b);
			return a;
		}
		poly operator % (const poly &a,const int &b){
			poly c(a);
			return c%=b;
		}
		poly inv(const poly &a,int k=-1){
			if(!~k)k=a.size();
			poly b{(int)qpow(a[0])};
			for(int i=1,x;i<k;i<<=1){
				x=min(i*2,k);
				(b*=poly({2})-a%x*b%x)%=x;
			}
			return b;
		}
		poly qiudao(const poly &a){
			int n=a.size();
			if(!n)return poly();
			poly b(n-1);
			for(int i=1;i<n;i++)b[i-1]=1ll*a[i]*i%mod;
			return b;
		}
		poly jifen(const poly &a){
			int n=a.size();
			if(!n)return poly(1);
			poly b(n+1);
			b[1]=1;
			for(int i=2;i<=n;i++)b[i]=1ll*b[mod%i]*(mod-mod/i)%mod;
			for(int i=1;i<=n;i++)b[i]=1ll*b[i]*a[i-1]%mod;
			return b;
		}
		poly ln(const poly &a,int k=-1){
			if(!~k)k=a.size();
			return jifen(qiudao(a)*inv(a,k)%k)%k;
		}
		poly exp(const poly &a,int k=-1){
			if(!~k)k=a.size();
			poly b(1);
			b[0]=1;
			for(int i=1,x;i<k;i<<=1){
				x=min(i*2,k);
				(b*=poly({1})-ln(b,x)+a%x)%=x;
			}
			return b;
		}
		poly sqrt(const poly &a,int k=-1){
			if(a.empty())return poly();
			if(!~k)k=a.size();
			poly b(1);
			b[0]=sqr(a[0]);
			for(int i=1,x;i<k;i<<=1){
				x=min(i*2,k);
				b=b/2+a%x*inv(b*2,x)%x;
			}
			return b;
		}
		poly operator << (const poly &a,const int &b){
			poly c(a.size()+b);
			copy(a.begin(),a.end(),c.begin()+b);
			return c;
		}
		poly operator <<= (poly &a,const int &b){
			return a=a<<b;
		}
		poly operator >> (const poly &a,const int &b){
			if(b>=a.size())return poly();
			return poly{a.begin()+b,a.end()};
		}
		poly operator >>= (poly &a,const int &b){
			return a=a>>b;
		}
		poly qpow(const poly &a,const ll &b,int k=-1){
			if(a.empty())return poly();
			if(!~k)k=a.size();
			int n=a.size(),st=0;
			for(;st<n&&!a[st];st++);
			if(st==n||(LL)st*b>=k)return poly(k);
			if(st)return qpow(a>>st,b,k-st*b)<<st*b;
			int x=a[0];
			return exp(ln(a/x,k)*(b%mod),k)*::qpow(x,b);
		}
		poly operator / (const poly &a,const poly &b){
			int n=a.size(),m=b.size(),k=n-m+1;
			if(k<=0)return poly();
			poly c(a),d(b);
			reverse(c.begin(),c.end());
			reverse(d.begin(),d.end());
			c=c%k*inv(d,k)%k;
			reverse(c.begin(),c.end());
			return c;
		}
		poly operator % (const poly &a,const poly &b){
			if(a.size()<b.size())return a;
			poly c=a/b;
			return a-b*c;
		}
		void div(const poly &a,const poly &b,poly &c,poly &d){
			if(a.size()<b.size()){
				c=poly(),d=a;
				return;
			}
			c=a/b,d=(a-b*c)%(b.size()-1);
		}
	}
}
using namespace Poly::Public;
posted @ 2023-11-30 07:53  A_zjzj  阅读(19)  评论(0编辑  收藏  举报