多項式全家桶板子

方便的

#define bin(x) (1<<(x))
int inv[maxn];
int ksm(int x,int y){int re=1;for(;(y&1?re=1ll*re*x%mod:0),y;y>>=1,x=1ll*x*x%mod);return re;}
#define INV(x) ksm(x,mod-2)
struct NTT{
	vector<int> w[30];NTT(){
		inv[1]=1;for(int i=2;i<=maxn-10;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
		for(int i=1,wn;i<=19;i++){
			w[i].resize(bin(i));w[i][0]=1;wn=ksm(3,(mod-1)/bin(i));
			for(int j=1;j<bin(i-1);j++)w[i][j]=1ll*w[i][j-1]*wn%mod;
		}
	}
	int limit,r[maxn];void dft(int *f,int lg,int type=0)
	{
		limit=bin(lg);if(type)reverse(f+1,f+limit);
		for(int i=1;i<limit;i++){r[i]=(r[i>>1]>>1)|((i&1)<<(lg-1));if(i<r[i])swap(f[i],f[r[i]]);}
		for(int mid=1,Lg=1;mid<limit;mid<<=1,Lg++)for(int j=0;j<limit;j+=(mid<<1))for(int i=0;i<mid;i++)
		{int t=1ll*f[j+i+mid]*w[Lg][i]%mod;f[j+i+mid]=(f[j+i]-t+mod)%mod;f[j+i]=(f[j+i]+t)%mod;}
	}
}ntt;
int A[maxn],B[maxn],C[maxn],M;
struct POLY{
	vector<int> a;int len;void rs(int N){a.resize(len=N);}POLY(){rs(M);};
	int &operator [](int x){return a[x];}
	friend POLY operator *(POLY A_,int x){for(int i=0;i<A_.len;i++)A_[i]=1ll*A_[i]*x%mod;return A_;}
	void dft(int *A_,int lg,int ln){for(int i=0;i<bin(lg);i++)A_[i]=(i<min(len,ln)?a[i]:0);ntt.dft(A_,lg);}
	void idft(int *A_,int lg,int ln){ntt.dft(A_,lg,1);rs(ln);for(int i=0;i<ln;i++)a[i]=1ll*A_[i]*inv[bin(lg)]%mod;}
	POLY Mul(POLY b,int ln=M){
		int lg=ceil(log2(2*ln-1));dft(A,lg,ln);b.dft(B,lg,ln);
		for(int i=0;i<bin(lg);i++)B[i]=1ll*A[i]*B[i]%mod;b.idft(B,lg,ln);return b;
	}
}F,G;
void getinv(POLY &f,POLY &g,int ln=M)
{
	if(ln==1){g.rs(1);g[0]=INV(f[0]);return;}getinv(f,g,(ln+1)>>1);
	int lg=ceil(log2(ln*2-1));f.dft(A,lg,ln);g.dft(B,lg,ln);
	for(int i=0;i<bin(lg);i++)B[i]=1ll*(2-1ll*A[i]*B[i]%mod+mod)%mod*B[i]%mod;g.idft(B,lg,ln);
}
POLY getinv(POLY &f,int ln=M){POLY g;getinv(f,g,ln);return g;};
POLY Jifen(POLY f){f.rs(f.len+1);for(int i=f.len-1;i>0;i--)f[i]=1ll*f[i-1]*inv[i]%mod;f[0]=0;return f;}
POLY Dao(POLY f){for(int i=0;i<f.len-1;i++)f[i]=1ll*f[i+1]*(i+1)%mod;f.rs(f.len-1);return f;}
POLY getln(POLY f,int ln=M){return Jifen(Dao(f).Mul(getinv(f,ln),ln-1));}
void getexp(POLY &f,POLY &g,int ln=M)
{
	if(ln==1){g.rs(1);g[0]=1;return;}getexp(f,g,(ln+1)>>1);
	POLY p=getln(g,ln);for(int i=0;i<ln;i++)p[i]=(f[i]-p[i]+mod)%mod;p[0]++;g=p.Mul(g,ln);
}
POLY getexp(POLY f,int ln){POLY g;getexp(f,g,ln);return g;}
POLY getksm(POLY f,int k,int k_,int ln=M)
{
	int st=0;while(!f[st]&&st<ln)st++;for(int i=0;i<ln;i++)f[i]=(i+st<ln?f[i+st]:0);
	int f_0=f[0];f_0=ksm(f_0,k_);f=getexp(getln(f*INV(f[0]),ln)*k,ln)*f_0;
	if(st)if(length<=9&&1ll*st*k<ln)for(int i=n-1;i>=0;i--)f[i]=(i>=st*k?f[i-st*k]:0);else f.rs(0),f.rs(ln); return f;
}
void getSqrt(POLY &f,POLY &g,int ln=M)
{
	if(ln==1){g.rs(1);g[0]=1;return;}getSqrt(f,g,(ln+1)>>1);POLY p=g*2,pp;getinv(p,pp,ln);
	int lg=ceil(log2(ln+ln-1));f.dft(A,lg,ln);g.dft(B,lg,ln);pp.dft(C,lg,ln);
	for(int i=0;i<bin(lg);i++)C[i]=1ll*(1ll*B[i]*B[i]%mod+A[i])%mod*C[i]%mod;g.idft(C,lg,ln);
}
POLY rev(POLY f){reverse(f.a.begin(),f.a.end());return f;}
POLY getdiv(POLY &f,POLY &g){return rev(rev(f).Mul(getinv(rev(g),f.len-g.len+1),f.len-g.len+1));}
POLY getmod(POLY &f,POLY &g){
	if(f.len<g.len)return f;POLY r=g.Mul(getdiv(f,g),f.len);
	for(int i=0;i<f.len;i++)r[i]=(f[i]-r[i]+mod)%mod;return r;
}
void fenzhi_fft(int l,int r,int d,int id){
	if(l==r){P[d][id].rs(2);P[d][id][0]=mod-a[l];P[d][id][1]=1;return;}
	fenzhi_fft(l,(l+r>>1),d+1,id<<1);fenzhi_fft((l+r>>1)+1,r,d+1,(id<<1)+1);
	P[d][id]=P[d+1][id<<1].Mul(P[d+1][(id<<1)+1],r-l+2);
}
void solve(int l,int r,POLY f,int d,int id)
{
	if(r-l+1<=16){for(int i=l,tot=0;i<=r;i++,tot=0){int x=1;
	for(int j=0;j<f.len;j++)tot=(tot+1ll*x*f[j])%mod,x=1ll*x*a[i]%mod;printf("%d\n",tot);}return;}
	solve(l,(l+r>>1),getmod(f,P[d+1][id<<1]),d+1,id<<1);
	solve((l+r>>1)+1,r,getmod(f,P[d+1][(id<<1)+1]),d+1,(id<<1)+1);
}

快的

#define bin(x) (1<<(x))
#define MS(F,x) memset(F,0,(4<<(x)))
int inv[maxn],log_2[maxn];
int ksm(int x,int y){int re=1;for(;(y&1?re=1ll*re*x%mod:0),y;y>>=1,x=1ll*x*x%mod);return re;}
#define INV(x) ksm(x,mod-2)
int *w[30];void prep(int N){//預處理原根
	inv[1]=1;for(int i=2;i<=N;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod,log_2[i]=ceil(log2(i));
	for(int i=1,wn;i<=log_2[N];i++){
		w[i]=new int[bin(i-1)];w[i][0]=1;wn=ksm(3,(mod-1)/(bin(i)));
		for(int j=1;j<bin(i-1);j++)w[i][j]=1ll*w[i][j-1]*wn%mod;
	}
}
int limit,r[maxn];void work(int lg){for(int i=1;i<bin(lg);i++)r[i]=(r[i>>1]>>1)|((i&1)<<(lg-1));}
void ntt(int *f,int lg,int type=0){//ntt板子
	limit=bin(lg);if(type)reverse(f+1,f+limit);
	for(int i=1;i<limit;i++)if(i<r[i])swap(f[i],f[r[i]]);
	for(int mid=1,Lg=1;mid<limit;mid<<=1,Lg++)for(int j=0;j<limit;j+=(mid<<1))for(int i=0;i<mid;i++)
	{int t=1ll*f[j+i+mid]*w[Lg][i]%mod;f[j+i+mid]=(f[j+i]-t+mod)%mod;f[j+i]=(f[j+i]+t)%mod;}
}
void NTT(int *f,int *g,int ln){
	int lg=log_2[ln*2-1];work(lg);
	ntt(f,lg);ntt(g,lg);for(int i=0;i<bin(lg);i++)f[i]=1ll*f[i]*g[i]%mod;
	ntt(f,lg,1);for(int i=0;i<bin(lg);i++)f[i]=i<ln?1ll*f[i]*inv[bin(lg)]%mod:0;
}
int A[maxn],B[maxn],C[maxn],D[maxn],E[maxn],H[maxn];
void getinv(int *f,int *g,int ln)//求逆
{
	if(ln==1){g[0]=INV(f[0]);return;}getinv(f,g,(ln+1)>>1);int lg=log_2[ln<<1];work(lg);
	MS(A,lg);MS(B,lg);memcpy(A,f,ln<<2);memcpy(B,g,ln<<2);
	ntt(A,lg);ntt(B,lg);for(int i=0;i<bin(lg);i++)A[i]=1ll*(2-1ll*A[i]*B[i]%mod+mod)%mod*B[i]%mod;
	ntt(A,lg,1);for(int i=0;i<ln;i++)g[i]=1ll*A[i]*inv[bin(lg)]%mod;
}
//求導求積分
void Dao(int *f,int *g,int ln){for(int i=0;i<ln-1;i++)g[i]=1ll*f[i+1]*(i+1)%mod;g[ln-1]=0;}
void Jifen(int *f,int *g,int ln){for(int i=ln-1;i>0;i--)g[i]=1ll*f[i-1]*inv[i]%mod;g[0]=0;}
void getln(int *f,int *g,int ln){//求ln
	MS(C,log_2[2*ln]);MS(D,log_2[2*ln]);
	getinv(f,C,ln);Dao(f,D,ln);NTT(C,D,ln);Jifen(C,g,ln);
}
void getexp(int *f,int *g,int ln)//求exp
{
	if(ln==1){g[0]=1;return;}getexp(f,g,(ln+1)>>1);
	MS(E,log_2[ln*2]);getln(g,E,ln);
	for(int i=0;i<ln;i++)E[i]=(f[i]-E[i]+mod)%mod;E[0]++;NTT(g,E,ln);
}
void getksm(int *f,int *g,int ln)//求快速冪
{
	int st=0;while(!f[st]&&st<ln)st++;for(int i=0;i<ln;i++)f[i]=(i+st<ln?f[i+st]:0);
	int f_0=ksm(f[0],k_);for(int i=0,in=INV(f[0]);i<ln;i++)f[i]=1ll*f[i]*in%mod;
	getln(f,g,ln);for(int i=0;i<ln;i++)f[i]=1ll*g[i]*k%mod,g[i]=0;getexp(f,g,ln);
	if(st)if(length<=9&&1ll*st*k<ln)for(int i=ln-1;i>=0;i--)g[i]=(i>=st*k?g[i-st*k]%mod:0);
	else MS(g,log_2[ln]); for(int i=0;i<ln;i++)g[i]=1ll*g[i]*f_0%mod;
}
void getsqrt(int *f,int *g,int ln)//開根
{
	if(ln==1){g[0]=1;return;}getsqrt(f,g,(ln+1)>>1);
	int lg=log_2[ln*2-1];MS(D,lg);MS(E,lg);memcpy(D,f,ln<<2);memcpy(E,g,ln<<2);
	for(int i=0;i<ln;i++)g[i]=2ll*g[i]%mod;MS(C,lg);getinv(g,C,ln);work(lg);
	ntt(E,lg);ntt(D,lg);ntt(C,lg);for(int i=0;i<bin(lg);i++)D[i]=1ll*(1ll*E[i]*E[i]%mod+D[i])%mod*C[i]%mod;
	ntt(D,lg,1);for(int i=0;i<ln;i++)g[i]=1ll*D[i]*inv[bin(lg)]%mod;
}
void rev(int *f,int *g,int ln){for(int i=0;i<ln;i++)g[i]=f[ln-1-i];}
void getdiv(int *f,int *g,int *q,int ln1,int ln2){//求商
	MS(C,log_2[ln1*2]);MS(D,log_2[ln1*2]);rev(f,C,ln1);rev(g,D,ln2);
	for(int i=ln1-ln2+1;i<ln1;i++)C[i]=D[i]=0;
	MS(E,log_2[ln1*2]);getinv(D,E,ln1-ln2+1);NTT(C,E,ln1-ln2+1);rev(C,q,ln1-ln2+1);
}
void getmod(int *f,int *g,int *q,int *r,int ln1,int ln2){//取模
	MS(A,log_2[ln1*2]);MS(B,log_2[ln1*2]);memcpy(A,g,ln1<<2);memcpy(B,q,ln1<<2);
	NTT(A,B,ln1);for(int i=0;i<ln2-1;i++)r[i]=(f[i]-A[i]+mod)%mod;
}
void getmod(int *f,int *g,int *r,int ln1,int ln2){
	if(ln1<ln2){memcpy(r,f,ln1<<2);return;}
	MS(H,log_2[ln1*2]);getdiv(f,g,H,ln1,ln2);getmod(f,g,H,r,ln1,ln2);
}
int *P[maxn],*R[maxn];inline int kk(int d,int id){return (1<<d)+id;}
void FZ_FFT(int l,int r,int d,int id)//給下面的做輔助
{
	P[kk(d,id)]=new int[bin(log_2[r-l+2]+1)];R[kk(d,id)]=new int[bin(log_2[r-l+2]+1)];
	if(l==r){P[kk(d,id)][0]=mod-a[l];P[kk(d,id)][1]=1;return;}
	int mid=l+r>>1;FZ_FFT(l,mid,d+1,id<<1);FZ_FFT(mid+1,r,d+1,(id<<1)+1);
	MS(P[kk(d,id)],log_2[r-l+2]+1);MS(E,log_2[r-l+2]+5);
	memcpy(P[kk(d,id)],P[kk(d+1,id<<1)],(mid-l+2)<<2);memcpy(E,P[kk(d+1,(id<<1)+1)],(r-mid+1)<<2);
	NTT(P[kk(d,id)],E,r-l+2);
}
void evalu(int l,int r,int *FA,int ln,int d,int id)//多點求值
{
	getmod(FA,P[kk(d,id)],R[kk(d,id)],ln,r-l+2);
	if(r-l+1<=16){for(int i=l,tot=0;i<=r;i++,tot=0){int x=1;
	for(int j=0;j<r-l+2;j++)tot=(tot+1ll*x*R[kk(d,id)][j])%mod,x=1ll*x*a[i]%mod;printf("%d\n",tot);}return;}
	int mid=l+r>>1;evalu(l,mid,R[kk(d,id)],r-l+2,d+1,id<<1);evalu(mid+1,r,R[kk(d,id)],r-l+2,d+1,(id<<1)+1);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章