多项式全家桶
放个板子
#define ll long long
#define cri const register int
#define re register
#define int ll
#define cp const cplx
using namespace std;
#define vcp vector<cplx>
#define vdb vector<double>
#define vnt vector<int>
#define cp const cplx
#define rs(x) x.resize(bin)
#define P 3.141592653589793L
const int lim=(1<<15);
const int mod=998244353;
inline void db(vnt &a,cri bin){
for(int i=0;i<bin;i++) cout<<a[i]<<" "; puts("");
}
inline ll qpow(ll a,ll b,ll ans=1){
for(;b;b>>=1,a=a*a%mod) if(b&1) ans=ans*a%mod;
return ans;
}
inline void rnt(vnt &A,cri bin){
rs(A);
for(int i=0;i<bin;i++) A[i]=0;
}
inline int r(double x){
return (int)(x+0.5);
}
inline int mo(cri x){
return x>=mod?x-mod:x;
}
struct cplx{
double rl,ig;
cplx(double r=0,double i=0){ this->rl=r;this->ig=i; }
friend cplx operator + (const cplx &a,const cplx &b){
return cplx(a.rl+b.rl,a.ig+b.ig);
}
friend cplx operator - (const cplx &a,const cplx &b){
return cplx(a.rl-b.rl,a.ig-b.ig);
}
friend cplx operator * (const cplx &a,const cplx &b){
return cplx(a.rl*b.rl-a.ig*b.ig,a.rl*b.ig+b.rl*a.ig);
}
};
vcp ww[19];
inline void put(vnt &A,cri bin){
for(int i=0;i<bin;i++) printf("%d ",A[i]);puts("");
}
struct node{
vnt pd[250010];
inline void clear(vnt &A,cri len,cri bin){ for(int i=len;i<bin;i++) A[i]=0; }
inline void ntt(vnt &A,cri bin,cri opt){
vnt v;rnt(v,bin);
for(int i=0;i<bin;i++) v[i]=v[i>>1]>>1|(i&1?bin>>1:0);//,cout<<v[i]<<" ";puts("");
for(int i=0;i<bin;i++) if(i<v[i]) swap(A[i],A[v[i]]);
for(int i=1;i<bin;i<<=1){
const ll wn=qpow(3,opt*(mod-1)/(i<<1)+mod-1);
for(int j=0,w=1;j<bin;j+=(i<<1),w=1)
for(int k=0;k<i;k++,w=w*wn%mod) {
ll x=A[j+k],y=w*A[j+k+i]%mod;
A[j+k]=mo(x+y);A[j+k+i]=mo(x-y+mod);
}
}
if(opt==-1) for(int i=0,pw=qpow(bin,mod-2);i<bin;i++) A[i]=A[i]*pw%mod;
}
inline void fft(vcp &A,cri bin,cri opt){
vnt v;rnt(v,bin);
for(int i=0;i<bin;i++) v[i]=v[i>>1]>>1|(i&1?bin>>1:0);
for(int i=0;i<bin;i++) if(i<v[i]) swap(A[i],A[v[i]]);
for(int i=1,g=0;i<bin;i<<=1,g++)
for(int j=0;j<bin;j+=(i<<1))
for(int k=0;k<i;k++){
cp x=A[j+k],y=ww[g][k]*A[j+k+i];
A[j+k]=x+y;A[j+k+i]=x-y;
}
if(opt==1) return;
reverse(A.begin()+1,A.begin()+bin);
for(int i=0;i<bin;i++) A[i].rl/=bin;
}
inline void mul(vnt &A,vnt &B,cri bin,cri opt){
if(!opt){
ntt(A,bin,1);ntt(B,bin,1);
for(int i=0;i<bin;i++) A[i]=A[i]*B[i]%mod;
ntt(A,bin,-1);ntt(B,bin,-1);
}
else {
vcp p1,p2,p3,p4;rs(p1);rs(p2);rs(p3);rs(p4);
for(int i=0;i<bin;i++)
p1[i]=cplx(A[i]>>15,0),p2[i]=cplx(A[i]&(lim-1),0),
p3[i]=cplx(B[i]>>15,0),p4[i]=cplx(B[i]&(lim-1),0);
fft(p2,bin,1);fft(p4,bin,1);fft(p3,bin,1);fft(p1,bin,1);
for(int i=0;i<bin;i++){
const cplx a=p1[i],b=p2[i],c=p3[i],d=p4[i];
p1[i]=a*c;p2[i]=(b*c)+(a*d);p3[i]=d*b;
}
fft(p3,bin,-1);fft(p1,bin,-1);fft(p2,bin,-1);
for(int i=0;i<bin;i++)
A[i]=(r(p1[i].rl)%mod*lim%mod*lim%mod+r(p2[i].rl)%mod*lim%mod+r(p3[i].rl))%mod;
}
}
void inv(vnt &A,vnt &B,cri len,cri opt){
if(len==1) return B[0]=qpow(A[0],mod-2),void();
inv(A,B,len+1>>1,opt);
int bin=1;
while(bin<len+len) bin<<=1;
vnt t1,t2;rnt(t1,bin);rnt(t2,bin);
for(int i=0;i<len;i++) t1[i]=A[i],t2[i]=B[i];
clear(B,len,bin);
mul(t1,t2,bin,opt);
clear(t1,len,bin);
mul(t1,t2,bin,opt);
for(int i=0;i<len;i++) B[i]=(B[i]*2-t1[i]+mod)%mod;
}
void sqrt(vnt &A,vnt &B,cri len,cri opt){
if(len==1) return B[0]=1,void();
sqrt(A,B,len+1>>1,opt);
int bin=1;
while(bin<len+len) bin<<=1;
vnt t3,t4,tmp;rnt(t3,bin);rnt(t4,bin);rnt(tmp,bin);
for(int i=0;i<len;i++) t3[i]=A[i],t4[i]=B[i];
clear(B,len,bin);
inv(t4,tmp,len,opt);
mul(t3,tmp,bin,opt);
for(int i=0,p=qpow(2,mod-2);i<len;i++) B[i]=(t3[i]+B[i])*p%mod;
}
inline void dao(vnt &A,vnt &B,cri bin){
for(int i=1;i<bin;i++) B[i-1]=A[i]*i%mod;B[bin-1]=0;
}
inline void jifen(vnt &A,vnt &B,cri bin){
for(int i=1;i<bin-1;i++) B[i]=A[i-1]*qpow(i,mod-2)%mod;B[0]=0;
}
inline void ln(vnt &A,vnt &B,cri len,cri opt,int bin=1){
while(bin<len+len) bin<<=1;
vnt t5,t6;rnt(t5,bin);rnt(t6,bin);
inv(A,t5,len,opt);
dao(A,t6,bin);
mul(t5,t6,bin,opt);
jifen(t5,B,bin);
}
void exp(vnt &A,vnt &B,cri len,cri opt,int bin=1){
if(len==1) return B[0]=1,void();
exp(A,B,len+1>>1,opt);
while(bin<len+len) bin<<=1;
vnt t7;rnt(t7,bin);
clear(B,len,bin);
ln(B,t7,len,opt);
for(int i=0;i<len;i++) t7[i]=mo(A[i]-t7[i]+mod);t7[0]++;
mul(B,t7,bin,opt);clear(B,len,bin);
}
void prod(cri k,vnt &A,cri l,cri r,cri n,cri opt,int bin=1){
while(bin<=n) bin<<=1;rnt(pd[k],bin<<1);
if(l==r) return pd[k][0]=mod-A[l],pd[k][1]=1,void();
cri mid=l+r>>1,L=k<<1,R=L|1;;
prod(L,A,l,mid,mid-l+1,opt);prod(R,A,mid+1,r,r-mid,opt);
ntt(pd[L],bin,1);ntt(pd[R],bin,1);
for(int i=0;i<bin;i++) pd[k][i]=pd[L][i]*pd[R][i]%mod;
ntt(pd[L],bin,-1);ntt(pd[R],bin,-1);ntt(pd[k],bin,-1);
}
void div(vnt &F,vnt &G,vnt &PP,vnt &Q,cri n,cri m,cri opt){
if(n<m) return Q=F,void();
vnt G0=G,invG;int bin=1,M=min(m+1,n-m+1);
while(bin<M+M) bin<<=1;
rnt(invG,bin);
for(int i=0;i<M;i++) PP[i]=F[n-i];
reverse(G0.begin(),G0.begin()+m+1);//put(G0,bin);
inv(G0,invG,M,opt);
mul(PP,invG,bin,opt);
reverse(PP.begin(),PP.begin()+M);clear(PP,M,bin);
Q=G;mul(Q,PP,Q.size(),opt);
for(int i=0;i<m;i++) Q[i]=mo(F[i]-Q[i]+mod);
}
void solve(cri k,vnt &A,vnt &ANS,cri l,cri r,cri n,cri opt){
if(l==r){ ANS[l]=A[0];return; }
int mid=l+r>>1,L=k<<1,R=L|1,bin=1;
while(bin<=n+n) bin<<=1;
vnt q1,q2;
rnt(q1,bin);rnt(q2,bin);
div(A,pd[L],q1,q2,n,mid-l+1,opt);
solve(L,q2,ANS,l,mid,mid-l,opt);
rnt(q1,bin);rnt(q2,bin);
div(A,pd[R],q1,q2,n,r-mid,opt);
solve(R,q2,ANS,mid+1,r,r-mid-1,opt);
}
void fst_get(vnt &A,vnt &ND,vnt &ANS,cri n,cri m,cri opt,int bin=1){
prod(1,ND,1,m,m,0);
solve(1,A,ANS,1,m,n,0);
}
}ntt;
signed main(){
}
${\color{Teal} 只}$${\color{Teal} 是}$${\color{Teal} 拼}$${\color{Teal} 凑}$${\color{Teal} 出}$${\color{Teal} 与}$${\color{Teal} 你}$${\color{Teal} 在}$${\color{Teal} 一}$${\color{Teal} 起}$${\color{Teal} 的}$${\color{Teal} 时}$${\color{Teal} 间}$