zoukankan      html  css  js  c++  java
  • 现行 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 缝合版
    
  • 相关阅读:
    装饰器的理解和使用
    策略模式的理解
    mongo 多条件or
    不止代码 == 摘读
    egret打包android + android微信登录--小结
    springboot整合mongo多数据源
    SpringBoot集成JWT 实现接口权限认证
    nginx反向代理使用网址速度变慢
    2017年2月总结
    (转)Mac os x 下配置Intellij IDEA + Tomcat 出现权限问题的解决办法
  • 原文地址:https://www.cnblogs.com/happydef/p/15610967.html
Copyright © 2011-2022 走看看