现行 poly 板子

Code
#include<bits/stdc++.h>
#define endl '\n' 
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
const int P=998244353,G=3,LIMIT=50;
union mi{
	int w;
	mi(){w=0;}
	mi(int u){u%=P,w=u+(u<0?P:0);}
	explicit operator int()const{return w;}
};
mi operator+(const mi&a,const mi&b){
	return mi(a.w+b.w-(a.w+b.w>=P?P:0));
}
mi operator-(const mi&a,const mi&b){
	return mi(a.w-b.w+(a.w<b.w?P:0));
}
mi operator*(const mi&a,const mi&b){
	return mi(1ll*a.w*b.w%P);
}
bool operator==(const mi&a,const mi&b){
	return a.w==b.w;
}
bool operator!=(const mi&a,const mi&b){
	return a.w!=b.w;
}
bool operator<(const mi&a,const mi&b){
	return a.w<b.w;
}
bool operator>(const mi&a,const mi&b){
	return a.w>b.w;
}
bool operator>=(const mi&a,const mi&b){
	return a.w>=b.w;
}
bool operator<=(const mi&a,const mi&b){
	return a.w<=b.w;
}
mi&operator+=(mi&a,const mi&b){
	a.w=a.w+b.w-(a.w+b.w>=P?P:0);
	return a;
}
mi&operator-=(mi&a,const mi&b){
	a.w=a.w-b.w+(a.w<b.w?P:0);
	return a;
}
mi&operator*=(mi&a,const mi&b){
	a.w=1ll*a.w*b.w%P;
	return a;
}
mi operator-(const mi&a){
	return mi(a.w?P-a.w:0);
}
mi&operator++(mi&a){
	a.w=a.w+1-(a.w+1>=P?P:0);
	return a;
}
mi&operator--(mi&a){
	a.w=a.w-1+(a.w?0:P);
	return a;
}
typedef vector<mi> vec;
struct IO_Tp {
    const static int _I_Buffer_Size = 2 << 22;
    char _I_Buffer[_I_Buffer_Size], *_I_pos = _I_Buffer;

    const static int _O_Buffer_Size = 2 << 22;
    char _O_Buffer[_O_Buffer_Size], *_O_pos = _O_Buffer;

    IO_Tp() { fread(_I_Buffer, 1, _I_Buffer_Size, stdin); }
    ~IO_Tp() { fwrite(_O_Buffer, 1, _O_pos - _O_Buffer, stdout); }

    IO_Tp &operator>>(int &res) {
    	int f=1;
        while (!isdigit(*_I_pos)&&(*_I_pos)!='-') ++_I_pos;
        if(*_I_pos=='-')f=-1,++_I_pos;
        res = *_I_pos++ - '0';
        while (isdigit(*_I_pos)) res = res * 10 + (*_I_pos++ - '0');
        res*=f;
        return *this;
    }
    
    IO_Tp &operator>>(mi &res) {
    	int f=1;
        while (!isdigit(*_I_pos)&&(*_I_pos)!='-') ++_I_pos;
        if(*_I_pos=='-')f=-1,++_I_pos;
        res = *_I_pos++ - '0';
        while (isdigit(*_I_pos)) res = res * 10 + (*_I_pos++ - '0');
        res*=f;
        return *this;
    }

    IO_Tp &operator<<(int n) {
    	if(n<0)*_O_pos++='-',n=-n;
        static char _buf[10];
        char *_pos = _buf;
        do
            *_pos++ = '0' + n % 10;
        while (n /= 10);
        while (_pos != _buf) *_O_pos++ = *--_pos;
        return *this;
    }
    
    IO_Tp &operator<<(mi n) {
    	if(n<0)*_O_pos++='-',n=-n;
        static char _buf[10];
        char *_pos = _buf;
        do
            *_pos++ = '0' + n.w % 10;
        while (n.w /= 10);
        while (_pos != _buf) *_O_pos++ = *--_pos;
        return *this;
    }

    IO_Tp &operator<<(char ch) {
        *_O_pos++ = ch;
        return *this;
    }
} IO;
void chkmax(int &x,int y){if(x<y)x=y;}
void chkmin(int &x,int y){if(x>y)x=y;}
int qpow(int a,int k,int p=P){
	int ret=1;
	while(k){
		if(k&1)ret=1ll*ret*a%p;
		a=1ll*a*a%p;
		k>>=1;
	}
	return ret;
}
int norm(int x){return x>=P?x-P:x;}
int reduce(int x){return x<0?x+P:x;}
void add(int&x,int y){if((x+=y)>=P)x-=P;}
struct Maths{
	int n;
	vec fac,invfac,inv;
	void build(int n){
		this->n=n;
		fac.resize(n+1);
		invfac.resize(n+1);
		inv.resize(n+1);
		fac[0]=1;
		rep(k,1,n)fac[k]=fac[k-1]*k;
		inv[1]=inv[0]=1;
		rep(k,2,n)inv[k]=-(P/k)*inv[P%k];
		invfac[0]=1;
		rep(k,1,n)invfac[k]=invfac[k-1]*inv[k];
	}
	Maths(){build(1);}
	void chk(int k){
		int lmt=n;
		if(k>lmt){while(k>lmt)lmt<<=1;build(lmt);}
	}
	mi cfac(int k){return chk(k),fac[k];}
	mi cifac(int k){return chk(k),invfac[k];}
	mi cinv(int k){return chk(k),inv[k];}
	mi binom(int n,int m){
		if(m<0||m>n)return 0;
		return cfac(n)*cifac(m)*cifac(n-m);
	}
}math;
struct NumberTheory{
	mt19937 rng;
	NumberTheory():rng(chrono::steady_clock::now().time_since_epoch().count()){}
	void exgcd(int a,int b,int&x,int&y){
		if(!b)return x=1,y=0,void();
		exgcd(b,a%b,y,x);
		y-=a/b*x;
	}
	int inv(int a,int p=P){
		int x,y;
		exgcd(a,p,x,y);
		if(x<0)x+=p;
		return x;
	}
	template<class Integer>
	bool quadRes(Integer a,Integer b){
		if(a<=1)return 1;
		while(a%4==0)a/=4;
		if(a%2==0)return (b%8==1||b%8==7)==quadRes(a/2,b);
		return ((a-1)%4==0||(b-1)%4==0)==quadRes(b%a,a);
	}
	int sqrt(int x,int p=P){
		if(p==2||x<=1)return x;
		int w,v,k=(p+1)/2;
		do w=rng()%p;while(quadRes((v=(1ll*w*w%p-x+p)%p),p));
		pair<int,int>res(1,0),a(w,1);
		while(k){
			if(k&1)res=make_pair((1ll*res.first*a.first%p+1ll*res.second*a.second%p*v%p)%p,
								  (1ll*res.first*a.second%p+1ll*res.second*a.first%p)%p);
			if(k>>=1)
				a=make_pair((1ll*a.first*a.first%p+1ll*a.second*a.second%p*v%p)%p,
							 2ll*a.first*a.second%p);
		}
		return min(res.first,p-res.first);
	}
}nt;
struct NTT{
	int L,brev[1<<11];
	vec root;
	NTT():L(-1){
		rep(i,1,(1<<11)-1)brev[i]=brev[i>>1]>>1|((i&1)<<10);
	}
	void preproot(int l){
		L=l;
		root.resize(2<<L);
		rep(i,0,L){
			mi*w=root.data()+(1<<i);
			w[0]=1;
			int omega=qpow(G,(P-1)>>i);
			rep(j,1,(1<<i)-1)w[j]=w[j-1]*omega;
		}
	}
	void dft(mi*a,int lgn,int d=1){
		if(L<lgn)preproot(lgn);
		int n=1<<lgn;
		rep(i,0,n-1){
			int rev=(brev[i>>11]|(brev[i&((1<<11)-1)]<<11))>>((11<<1)-lgn);
			if(i<rev)swap(a[i],a[rev]);
		}
		for(int i=1;i<n;i<<=1){
			mi*w=root.data()+(i<<1);
			for(int j=0;j<n;j+=i<<1)rep(k,0,i-1){
				mi aa=w[k]*a[i+j+k];
				a[i+j+k]=a[j+k]-aa;
				a[j+k]+=aa;
			}
		}
		if(d==-1){
			reverse(a+1,a+n);
			int inv=nt.inv(n);
			rep(i,0,n-1)a[i]*=inv;
		}
	}
}ntt;
struct poly{
	vec a;
	poly(mi v):a(1){a[0]=v;}
	poly(int v=0):a(1){a[0]=v;}
	poly(const vec&a):a(a){}
	poly(initializer_list<mi>init):a(init){}
	mi operator[](int k)const{return k<a.size()?a[k]:0;}
	mi&operator[](int k){
		if(k>=a.size())a.resize(k+1);
		return a[k];
	}
	int deg()const{return a.size()-1;}
	void redeg(int d){a.resize(d+1);}
	poly slice(int d)const{
		if(d<a.size())return vec(a.begin(),a.begin()+d+1);
		vec res(a);
		res.resize(d+1);
		return res;
	}
	mi*base(){return a.data();}
	const mi*base()const{return a.data();}
	poly println(FILE* fp=stdout)const{
		fprintf(fp,"%d",a[0]);
		rep(i,1,a.size()-1)fprintf(fp," %d",a[i]);
		fputc('\n',fp);
		return *this;
	}
	poly operator+(const poly&rhs)const{
		vec res(max(a.size(),rhs.a.size()));
		rep(i,0,res.size()-1)res[i]=operator[](i)+rhs[i];
		return res;
	}
	poly operator-()const{
		poly ret(a);
		rep(i,0,a.size()-1)ret[i]=-ret[i];
		return ret;
	}
	poly operator-(const poly&rhs)const{return operator+(-rhs);}
	poly operator*(const poly&rhs)const;//done
	poly operator/(const poly&rhs)const;//done
	poly operator%(const poly&rhs)const;//done
	poly der()const;//done
	poly integ()const;//done
	poly inv()const;//done
	poly sqrt()const;//done
	poly ln()const;//done
	poly exp()const;//done
	poly sin()const;//done
	poly cos()const;//done
	poly arcsin()const;//done
	poly arctan()const;//done
	pair<poly,poly>sqrti()const;//done
	pair<poly,poly>expi()const;//done
	poly quo(const poly&rhs)const;//done
	pair<poly,poly>iquo(const poly&rhs)const;
	pair<poly,poly>div(const poly&rhs)const;//done
	poly taylor(int k)const;
	poly pow(int k)const;//done
	poly exp(int k)const;//done
	poly shift(int k)const;//done
	mi LHRR(const vec&a,int n)const;//done
	mi LNRR(const poly&P,const vec&a,int n)const;
};
poly zeroes(int deg){return vec(deg+1);}
struct Newton{
	void inv(const poly&f,const poly&nttf,poly&g,const poly&nttg,int t){
		int n=1<<t;
		poly prod=nttf;
		rep(i,0,(n<<1)-1)prod[i]=prod[i]*nttg[i];
		ntt.dft(prod.base(),t+1,-1);
		rep(i,0,n-1)prod[i]=0;
		ntt.dft(prod.base(),t+1,1);
		rep(i,0,(n<<1)-1)prod[i]=prod[i]*nttg[i];
		ntt.dft(prod.base(),t+1,-1);
		rep(i,0,n-1)prod[i]=0;
		g=g-prod;
	}
	void inv(const poly&f,const poly&nttf,poly&g,int t){
		poly nttg=g;
		nttg.redeg((2<<t)-1);
		ntt.dft(nttg.base(),t+1,1);
		inv(f,nttf,g,nttg,t);
	}
	void inv(const poly&f,poly&g,int t){
		poly nttg=g;
		nttg.redeg((2<<t)-1);
		ntt.dft(nttg.base(),t+1,1);
		poly nttf=f;
		nttf.redeg((2<<t)-1);
		ntt.dft(nttf.base(),t+1,1);
		inv(f,nttf,g,nttg,t);
	}
	void sqrt(const poly&f,poly&g,poly&nttg,poly&h,int t){
		rep(i,0,(1<<t)-1)nttg[i]=qpow(int(nttg[i]),2);
		ntt.dft(nttg.base(),t,-1);
		nttg=nttg-f;
		rep(i,0,(1<<t)-1)nttg[i+(1<<t)]+=nttg[i];
		memset(nttg.base(),0,sizeof(mi)<<t);
		ntt.dft(nttg.base(),t+1,1);
		poly tmp=h;
		tmp.redeg((2<<t)-1);
		ntt.dft(tmp.base(),t+1,1);
		rep(i,0,(2<<t)-1)tmp[i]*=nttg[i];
		ntt.dft(tmp.base(),t+1,-1);
		memset(tmp.base(),0,sizeof(mi)<<t);
		g=g-tmp*mi(499122177);
	}
	void exp(const poly&f,poly&g,poly&nttg,poly&h,int t){
		poly ntth(h);
		ntt.dft(ntth.base(),t,1);
		poly dg=g.der().slice((1<<t)-1);
		ntt.dft(dg.base(),t,1);
		poly tmp=zeroes((1<<t)-1);
		rep(i,0,(1<<t)-1){
			tmp[i]=nttg[i<<1]*ntth[i];
			dg[i]=dg[i]*ntth[i];
		}
		ntt.dft(tmp.base(),t,-1);
		ntt.dft(dg.base(),t,-1);
		if(--tmp[0]<0)tmp[0]=P-1;
		dg.redeg((2<<t)-1);
		poly df0=f.der().slice((1<<t)-1);
		df0[(1<<t)-1]=0;
		rep(i,0,(1<<t)-1)if((dg[i|1<<t]=dg[i]-df0[i])<0)dg[i|1<<t]+=P;
		memcpy(dg.base(),df0.base(),sizeof(mi)*((1<<t)-1));
		tmp.redeg((2<<t)-1);
		ntt.dft(tmp.base(),t+1,1);
		df0.redeg((2<<t)-1);
		ntt.dft(df0.base(),t+1,1);
		rep(i,0,(2<<t)-1)df0[i]*=df0[i]*tmp[i];
		ntt.dft(df0.base(),t+1,-1);
		memcpy(df0.base()+(1<<t),df0.base(),sizeof(mi)<<t);
		memset(df0.base(),0,sizeof(mi)<<t);
		dg=(dg-df0).integ().slice((2<<t)-1)-f;
		ntt.dft(dg.base(),t+1,1);
		rep(i,0,(2<<t)-1)tmp[i]=dg[i]*nttg[i];
		ntt.dft(tmp.base(),t+1,-1);
		g.redeg((2<<t)-1);
		rep(i,1<<t,(2<<t)-1)if(tmp[i]!=0)g[i]=P-tmp[i];
	}
}nit;
struct SemiRelaxedConvolution{
	template<class Function>
	void run(const vec&a,vec&b,const Function&relax){
		int n=a.size()-1;
		function<void(int,int)>cdq = [&](int l,int r){
			if(r-l<=LIMIT){
				rep(i,l,r){
					rep(j,l,i-1)b[i]+=b[j]*a[i-j];
					relax(i);
				}
				return;
			}
			int lg=31-__builtin_clz(r-l),d=(r-l)/lg+1,lgd=0;
			while((1<<lgd)<d)++lgd;++lgd;
			vec top(lg<<(lgd+1));
			rep(i,0,lg-1){
				copy(a.begin()+i*d,a.begin()+min((i+2)*d,n+1),top.begin()+(i<<lgd));
				ntt.dft(top.data()+(i<<lgd),lgd,1);
			}
			rep(i,0,lg-1){
				if(i)ntt.dft(top.data()+((lg+i)<<lgd),lgd,-1);
				rep(j,0,min(d,r-l-i*d+1)-1)b[l+i*d+j]+=top[((lg+i)<<lgd)+d+j];
				cdq(l+i*d,min(l+(i+1)*d-1,r));
				if(i+1<lg){
					copy(b.begin()+l+i*d,b.begin()+min(l+(i+1)*d,n+1),top.begin()+((lg+i)<<lgd));
					fill(top.data()+((lg+i)<<lgd)+d,top.data()+((lg+i+1)<<lgd),0);
					ntt.dft(top.data()+((lg+i)<<lgd),lgd,1);
				}
				rep(j,i+1,lg-1)rep(k,0,(1<<lgd)-1)
					top[((lg+j)<<lgd)+k]+=top[((j-i-1)<<lgd)+k]*top[((lg+i)<<lgd)+k];
			}
		};
		cdq(0,n);
	}
}src;
struct Transposition{
	vec _mul(int l,vec res,const poly&b){
		vec tmp(1<<l);
		memcpy(tmp.data(),b.a.data(),sizeof(mi)*(b.deg()+1));
		reverse(tmp.begin()+1,tmp.end());
		ntt.dft(tmp.data(),l,1);
		rep(i,0,(1<<l)-1)res[i]*=tmp[i];
		ntt.dft(res.data(),l,-1);
		return res;
	}
	poly bfmul(const poly&a,const poly&b){
		int n=a.deg(),m=b.deg();
		poly ret=zeroes(n-m);
		rep(i,0,n-m)rep(j,0,m)ret[i]+=a[i+j]*b[j];
		return ret;
	}
	poly mul(const poly&a,const poly&b){
		if(a.deg()<b.deg())return 0;
		if(a.deg()<=LIMIT)return bfmul(a,b);
		int l=0;
		while((1<<l)<=a.deg())++l;
		vec res(1<<l);
		memcpy(res.data(),a.a.data(),sizeof(mi)*(a.deg()+1));
		ntt.dft(res.data(),l,1);
		res=_mul(l,res,b);
		res.resize(a.deg()-b.deg()+1);
		return res;
	}
	pair<poly,poly>mul2(const poly&a,const poly&b1,const poly&b2){
		if(a.deg()<=LIMIT)return make_pair(bfmul(a,b1),bfmul(a,b2));
		int l=0;
		while((1<<l)<=a.deg())++l;
		vec fa(1<<l);
		memcpy(fa.data(),a.a.data(),sizeof(mi)*(a.deg()+1));
		ntt.dft(fa.data(),l,1);
		vec res1=_mul(l,fa,b1),res2=_mul(l,fa,b2);
		res1.resize(a.deg()-b1.deg()+1);
		res2.resize(a.deg()-b2.deg()+1);
		return make_pair(res1,res2);
	}
	vector<int>ls,rs,pos;
	vector<poly>p,q;
	void _build(int n){
		ls.assign(n*2-1,0);
		rs.assign(n*2-1,0);
		p.assign(n*2-1,0);
		q.assign(n*2-1,0);
		pos.resize(n);
		int cnt=0;
		function<int(int,int)>dfs=[&](int l,int r){
			if(l==r){
				pos[l]=cnt;
				return cnt++;
			}
			int ret=cnt++;
			int mid=l+r>>1;
			ls[ret]=dfs(l,mid);
			rs[ret]=dfs(mid+1,r);
			return ret;
		};
		dfs(0,n-1);
	}
	vec _eval(vec f,const vec&x){
		int n=f.size();
		_build(n);
		rep(i,0,n-1)q[pos[i]]={1,-x[i]};
		Rep(i,n*2-2,0)if(ls[i])q[i]=q[ls[i]]*q[rs[i]];
		f.resize(n*2);
		p[0]=mul(f,q[0].inv());
		rep(i,0,n*2-2)if(ls[i])tie(p[ls[i]],p[rs[i]])=mul2(p[i],q[rs[i]],q[ls[i]]);
		vec ret(n);
		rep(i,0,n-1)ret[i]=p[pos[i]][0];
		return ret;
	}
	vec eval(const poly&f,const vec&x){
		int n=f.deg()+1,m=x.size();
		vec tmpf=f.a,tmpx=x;
		tmpf.resize(max(n,m));
		tmpx.resize(max(n,m));
		vec ret=_eval(tmpf,tmpx);
		ret.resize(m);
		return ret;
	}
	poly inter(const vec&x,const vec&y){
		int n=x.size();
		_build(n);
		rep(i,0,n-1)q[pos[i]]={1,-x[i]};
		Rep(i,n*2-2,0)if(ls[i])q[i]=q[ls[i]]*q[rs[i]];
		poly tmp=q[0];
		reverse(tmp.a.begin(),tmp.a.end());
		vec f=tmp.der().a;
		f.resize(n*2);
		p[0]=mul(f,q[0].inv());
		rep(i,0,n*2-2)if(ls[i])tie(p[ls[i]],p[rs[i]])=mul2(p[i],q[rs[i]],q[ls[i]]);
		rep(i,0,n-1)p[pos[i]]=nt.inv((int)p[pos[i]][0])*y[i];
		rep(i,0,n*2-2)reverse(q[i].a.begin(),q[i].a.end());
		Rep(i,n*2-2,0)if(ls[i])p[i]=p[ls[i]]*q[rs[i]]+p[rs[i]]*q[ls[i]];
		return p[0];
	}
}tp;
poly operator "" _z(unsigned long long a){return {0,(int)a};}
poly operator+(int v,const poly&rhs){return poly(v)+rhs;}
poly operator*(int v,const poly&rhs){
	poly ret=zeroes(rhs.deg());
	rep(i,0,rhs.deg())ret[i]=rhs[i]*v;
	return ret;
}
poly operator*(const poly&lhs,int v){return v*lhs;}
poly poly::operator*(const poly&rhs)const{
	int n=deg(),m=rhs.deg();
	if(n<=10||m<=10||n+m<=LIMIT){
		poly ret=zeroes(n+m);
		rep(i,0,n)rep(j,0,m)ret[i+j]+=a[i]*rhs[j];
		return ret;
	}
	n+=m;
	int l=0;
	while((1<<l)<=n)++l;
	vec res(1<<l),tmp(1<<l);
	memcpy(res.data(),base(),a.size()*sizeof(mi));
	ntt.dft(res.begin().base(),l,1);
	memcpy(tmp.data(),rhs.base(),rhs.a.size()*sizeof(mi));
	ntt.dft(tmp.begin().base(),l,1);
	rep(i,0,(1<<l)-1)res[i]*=tmp[i];
	ntt.dft(res.data(),l,-1);
	res.resize(n+1);
	return res;
}
poly poly::inv()const{
	poly g=nt.inv((int)a[0]);
	for(int t=0;(1<<t)<=deg();++t)nit.inv(slice((2<<t)-1),g,t);
	g.redeg(deg());
	return g;
}
poly poly::taylor(int k)const{
	int n=deg();
	poly t=zeroes(n);
	math.chk(n);
	rep(i,0,n)t[n-i]=a[i]*math.fac[i];
	int pw=1;
	poly help=vec(math.invfac.begin(),math.invfac.begin()+n+1);
	rep(i,0,n){
		help[i]*=pw;
		pw*=k;
	}
	t=t*help;
	rep(i,0,n)help[i]=t[n-i]*math.invfac[i];
	return help;
}
poly poly::pow(int k)const{
	if(k==0)return 1;
	if(k==1)return *this;
	int n=deg()*k;
	int lgn=0;
	while((1<<lgn)<=n)++lgn;
	vec val=a;
	val.resize(1<<lgn);
	ntt.dft(val.data(),lgn,1);
	rep(i,0,(1<<lgn)-1)val[i]=qpow((int)val[i],k);
	ntt.dft(val.data(),lgn,-1);
	return val;
}
poly poly::der()const{
	if(deg()==0)return 0;
	vec res(deg());
	rep(i,0,deg()-1)res[i]=a[i+1]*mi(i+1);
	return res;
}
poly poly::integ()const{
	vec res(deg()+2);
	rep(i,0,deg())res[i+1]=a[i]*math.cinv(i+1);
	return res;
}
poly poly::quo(const poly&rhs)const{
	if(rhs.deg()==0)return a[0]*(mi)nt.inv((int)rhs[0]);
	poly g=(mi)nt.inv((int)rhs[0]);
	int t=0,n;
	for(n=1;(n<<1)<=rhs.deg();++t,n<<=1)nit.inv(rhs.slice((n<<1)-1),g,t);
	poly nttg=g;
	nttg.redeg((n<<1)-1);
	ntt.dft(nttg.base(),t+1,1);
	poly eps1=rhs.slice((n<<1)-1);
	ntt.dft(eps1.base(),t+1,1);
	rep(i,0,(n<<1)-1)eps1[i]*=nttg[i];
	ntt.dft(eps1.base(),t+1,-1);
	memcpy(eps1.base(),eps1.base()+n,sizeof(mi)<<t);
	memset(eps1.base()+n,0,sizeof(mi)<<t);
	ntt.dft(eps1.base(),t+1,1);
	poly h0=slice(n-1);
	h0.redeg((n<<1)-1);
	ntt.dft(h0.base(),t+1,1);
	poly h0g0=zeroes((n<<1)-1);
	rep(i,0,(n<<1)-1)h0g0[i]=h0[i]*nttg[i];
	ntt.dft(h0g0.base(),t+1,-1);
	poly h0eps1=zeroes((n<<1)-1);
	rep(i,0,(n<<1)-1)h0eps1[i]=h0[i]*eps1[i];
	ntt.dft(h0eps1.base(),t+1,-1);
	rep(i,0,n-1)h0eps1[i]=operator[](i+n)-h0eps1[i];
	memset(h0eps1.base()+n,0,sizeof(mi)<<t);
	ntt.dft(h0eps1.base(),t+1,1);
	rep(i,0,(n<<1)-1)h0eps1[i]*=nttg[i];
	ntt.dft(h0eps1.base(),t+1,-1);
	memcpy(h0eps1.base()+n,h0eps1.base(),sizeof(mi)<<t);
	memset(h0eps1.base(),0,sizeof(mi)<<t);
	return (h0g0+h0eps1).slice(rhs.deg());
}
poly poly::ln()const{
	if(deg()==0)return 0;
	return der().quo(slice(deg()-1)).integ();
}
pair<poly,poly> poly::sqrti()const{
	poly g=nt.sqrt((int)a[0]),h=nt.inv((int)g[0]),nttg=g;
	for(int t=0;(1<<t)<=deg();++t){
		nit.sqrt(slice((2<<t)-1),g,nttg,h,t);
		if((2<<t)<=deg()){
			nttg=g;
			ntt.dft(nttg.base(),t+1,1);
			nit.inv(g,nttg,h,t);
		}
	}
	return make_pair(g.slice(deg()),h.slice(deg()));
}
poly poly::sqrt()const{
	poly g=nt.sqrt((int)a[0]),h=nt.inv((int)g[0]),nttg=g;
	for(int t=0;(1<<t)<=deg();++t){
		nit.sqrt(slice((2<<t)-1),g,nttg,h,t);
		if((2<<t)<=deg()){
			nttg=g;
			ntt.dft(nttg.base(),t+1,1);
			nit.inv(g,nttg,h,t);
		}
	}
	return g.slice(deg());
}
poly poly::exp()const{
	vec der(a),ret(a.size());
	rep(i,0,a.size()-1)der[i]*=i;
	src.run(der,ret,[&](int i){
		if(i==0)ret[0]=1;
		else ret[i]*=math.cinv(i);
	});
	return ret;
}
pair<poly,poly>poly::expi()const{
	poly g=1,h=1,nttg={1,1};
	for(int t=0;(1<<t)<=deg();++t){
		nit.exp(slice((2<<t)-1),g,nttg,h,t);
		nttg=g;
		nttg.redeg((4<<t)-1);
		ntt.dft(nttg.base(),t+2);
		poly f2n=zeroes((2<<t)-1);
		rep(i,0,(2<<t)-1)f2n[i]=nttg[i<<1];
		nit.inv(g,f2n,h,t);
	}
	return make_pair(g.slice(deg()),h.slice(deg()));
}
poly poly::exp(int k)const{
	int lead,lz=0;
	while(lz<deg()&&a[lz]==0)++lz;
	if(lz==deg()&&a[lz]==0)return *this;
	lead=(int)a[lz];
	if(1ll*lz*k>deg())return zeroes(deg());
	poly part=poly(vec(a.begin()+lz,a.begin()+deg()-lz*(k-1)+1))*nt.inv(lead);
	part=(part.ln()*k).exp()*qpow(lead,k);
	vec ret(deg()+1);
	memcpy(ret.data()+lz*k,part.base(),sizeof(mi)*(deg()-lz*k+1));
	return ret;
}
poly poly::sin()const{
	int imag=qpow(G,(P-1)>>2);
	poly g=operator*(imag),eif,ieif;
	tie(eif,ieif)=g.expi();
	return (eif-ieif)*nt.inv(imag*2%P);
}
poly poly::cos()const{
	int imag=qpow(G,(P-1)>>2);
	poly g=operator*(imag),eif,ieif;
	tie(eif,ieif)=g.expi();
	return (eif+ieif)*nt.inv(2);
}
poly poly::arcsin()const{
	return der().quo((poly(1)-pow(2).slice(deg()-1)).sqrt()).integ();
}
poly poly::arctan()const{
	return der().quo(poly(1)+pow(2).slice(deg()-1)).integ();
}
poly poly::operator/(const poly&rhs)const{
	int n=deg(),m=rhs.deg();
	if(n<m)return 0;
	poly ta(vec(a.rbegin(),a.rend())),tb(vec(rhs.a.rbegin(),rhs.a.rend()));
	ta.redeg(n-m),tb.redeg(n-m);
	poly q=ta.quo(tb);
	reverse(q.a.begin(),q.a.end());
	return q;
}
pair<poly,poly>poly::div(const poly&rhs)const{
	if(deg()<rhs.deg())return make_pair(0,*this);
	int n=deg(),m=rhs.deg();
	poly q=operator/(rhs),r;
	int lgn=0;
	while((1<<lgn)<rhs.deg())++lgn;
	int t=(1<<lgn)-1;
	r=zeroes(t);
	poly tmp=zeroes(t);
	rep(i,0,m)r[i&t]+=rhs[i];
	rep(i,0,n-m)tmp[i&t]+=q[i];
	ntt.dft(r.base(),lgn,1);
	ntt.dft(tmp.base(),lgn,1);
	rep(i,0,t)tmp[i]*=r[i];
	ntt.dft(tmp.base(),lgn,-1);
	memset(r.base(),0,sizeof(mi)<<lgn);
	rep(i,0,n)r[i&t]+=a[i];
	rep(i,0,m-1)r[i]-=tmp[i];
	return make_pair(q,r.slice(m-1));
}
poly poly::shift(int k)const{
	poly g=zeroes(deg()+k);
	rep(i,0,k-1)g[i]=0;
	rep(i,max(0,-k),deg())g[i+k]=a[i];
	return g;
}
int quo2(int x){return ((x&1)?(x+P):x)>>1;}
mi poly::LHRR(const vec&a,int n)const{
	int k=a.size();
	poly p=a,q=zeroes(k);
	q[0]=1;
	rep(i,1,k)q[i]=-this->a[i-1];
	p=(p*q).slice(k-1);
	int logk=0;
	while((1<<logk)<=k)++logk;++logk;
	int h=1<<(logk-1);
	vec sp,sq;
	if(ntt.L<logk)ntt.preproot(logk);
	while(n>=k){
		vec pdft(1<<logk),qdft(1<<logk);
		copy_n(p.base(),k,pdft.data());
		copy_n(q.base(),k+1,qdft.data());
		mi*w=ntt.root.data()+(1<<logk);
		if(sp.empty()){
			ntt.dft(pdft.data(),logk,1);
			ntt.dft(qdft.data(),logk,1);
		}else{
			vec odd(h);
			rep(i,0,k-1)odd[i]=w[i]*p[i];
			ntt.dft(odd.data(),logk-1,1);
			rep(i,0,h-1){
				pdft[i<<1]=sp[i];
				pdft[i<<1|1]=odd[i];
			}
			odd.assign(h,0);
			rep(i,0,k)odd[i]=w[i]*q[i];
			ntt.dft(odd.data(),logk-1,1);
			rep(i,0,h-1){
				qdft[i<<1]=sq[i];
				qdft[i<<1|1]=odd[i];
			}
		}
		sp.resize(h);
		sq.resize(h);
		if(n%2==0)rep(i,0,h-1)sp[i]=quo2(int(pdft[i]*qdft[i^h]+pdft[i^h]*qdft[i]));
		else{
			rep(i,0,h-1)sp[i]=quo2(int(pdft[i]*qdft[i^h]-pdft[i^h]*qdft[i]));
			rep(i,1,h-1)sp[i]=sp[i]*w[(1<<logk)-i];
		}
		vec tmp=sp;
		ntt.dft(tmp.data(),logk-1,-1);
		copy_n(tmp.data(),k,p.base());
		rep(i,0,h-1)sq[i]=qdft[i]*qdft[i^h];
		tmp=sq;
		ntt.dft(tmp.data(),logk-1,-1);
		copy_n(tmp.data(),k+1,q.base());
		n>>=1;
	}
	p=p.quo(q);
	return p[n];
}
mi poly::LNRR(const poly&P,const vec&a,int n)const{
	int m=P.deg(),k=a.size();
	vec d(m+1);
	rep(i,0,m)d[i]=i+k;
	vec b=tp.eval(P,d);
	b.resize(k+m+1);
	Rep(i,k+m,k)b[i]=b[i-k];
	memset(b.data(),0,sizeof(mi)*k);
	auto res=operator*(poly(a)).shift(1);
	rep(i,0,k-1)b[i]=a[i]-res[i];
	poly B(b),F=shift(1),A=B.quo((poly(1)-F).slice(m+k));
	F.redeg(m+1);
	rep(i,0,m+1)
		if((m+1-i)&1)F[i]=-math.binom(m+1,i);
		else F[i]=math.binom(m+1,i);
	int T=m+k;
	poly f=((shift(1)-1)*F);
	if(f[0]==1)f=-f;
	return f.shift(-1).slice(T).LHRR(A.a,n);
}
poly poly::operator%(const poly&rhs)const{
	if(deg()<rhs.deg())return *this;
	return div(rhs).second;
}
template<class T>
IO_Tp& operator>>(IO_Tp& IO,vector<T>&v){
	for(T&x:v)IO>>x;
	return IO;
}
template<class T>
IO_Tp& operator<<(IO_Tp& IO,vector<T>&v){
	for(T&x:v)IO<<x<<' ';
	return IO;
}
//hodf 缝合版
posted @ 2021-11-27 10:23  happydef  阅读(117)  评论(1编辑  收藏  举报