提出 #70710592
ソースコード 拡げる
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
#ifdef LOCAL
typedef long long LLL;
typedef unsigned long long uLLL;
#else
typedef __int128 LLL;
typedef unsigned __int128 uLLL;
#endif
typedef vector<int> poly;
typedef vector<int> Vec;
typedef vector<Vec> Mat;
typedef tuple<poly,poly,poly,poly> Mat2;
mt19937 rng(chrono::system_clock::now().time_since_epoch().count());
const int Mod=998244353,G=3;
const LL Mod2=(LL)Mod*Mod;
vector<uLL>Grt,iGrt;
poly frc({1,1}),inv({0,1}),ivf({1,1});
inline int qpow(int x,int y,int z=1){
for(;y;(y>>=1)&&(x=(LL)x*x%Mod))if(y&1)z=(LL)z*x%Mod;return z;
}
inline void Init(const int&n){
for(int i=frc.size();i<=n;++i)
frc.emplace_back((LL)frc.back()*i%Mod),
inv.emplace_back(Mod-Mod/i*(LL)inv[Mod%i]%Mod),
ivf.emplace_back((LL)ivf.back()*inv.back()%Mod);
}
inline int Binom(const int&n,const int&m){
if(n<m||m<0)return 0;
return Init(n),(LL)frc[n]*ivf[m]%Mod*ivf[n-m]%Mod;
}
inline uLL trans(const uLL&x){
constexpr uLL A=-(uLL)Mod/Mod+1;
constexpr uLL Q=(((uLLL)(-(uLL)Mod%Mod)<<64)+Mod-1)/Mod;
return x*A+(uLL)((uLLL)x*Q>>64)+1;
}
inline uLL mul(const uLL&x,const uLL&y){
return x*y*(uLLL)Mod>>64;
}
inline int add(int x,const int&y){
return ((x+=y)-Mod)>=0?x-Mod:x;
}
inline int sub(int x,const int&y){
return (x-=y)<0?x+Mod:x;
}
inline int div2(const int&x){
return x&1?(x+Mod)>>1:x>>1;
}
inline bool Empty(poly&P){
for(;!P.empty()&&!P.back();P.pop_back());
return P.empty();
}
inline poly Add(poly P,poly Q){
if(P.size()<Q.size())P.swap(Q);
for(int i=Q.size();i--;)P[i]=add(P[i],Q[i]);
return P;
}
inline poly Add_Empty(poly P,poly Q){
if(P.size()<Q.size())P.swap(Q);
for(int i=Q.size();i--;)P[i]=add(P[i],Q[i]);
return Empty(P),P;
}
inline poly Sub(poly P,poly Q){
if(P.size()<Q.size())P.resize(Q.size());
for(int i=Q.size();i--;)P[i]=sub(P[i],Q[i]);
return P;
}
inline poly Sub_Empty(poly P,poly Q){
if(P.size()<Q.size())P.resize(Q.size());
for(int i=Q.size();i--;)P[i]=sub(P[i],Q[i]);
return Empty(P),P;
}
inline poly Mulx(poly P,int x){
const uLL v=trans(x);
for(int&i:P)i=mul(i,v);
return P;
}
inline poly Neg(poly P){
for(int i=P.size();i--;)P[i]&&(P[i]=Mod-P[i]);
return P;
}
inline int Eval(poly&P,int x){
int z=0;
for(int i=P.size();i--;)z=((LL)z*x+P[i])%Mod;
return z;
}
inline poly invLinear(poly P){
const int n=P.size();
poly Q(n+1,1);
for(int i=0;i<n;++i)Q[i+1]=(LL)Q[i]*P[i]%Mod;
int t=qpow(Q[n],Mod-2);Q.pop_back();
for(int i=n;i--;)Q[i]=(LL)Q[i]*t%Mod,t=(LL)t*P[i]%Mod;
return Q;
}
inline void extend(const int&n){
if(Grt.empty())Grt.emplace_back(trans(1)),iGrt.emplace_back(trans(1));
if((int)Grt.size()<n){
int L=Grt.size();
for(Grt.resize(n),iGrt.resize(n);L<n;L*=2){
const int w=qpow(G,Mod/(L*4)),iw=qpow(w,Mod-2);
for(int i=0;i<L;++i)Grt[i+L]=trans(mul(Grt[i],w)),iGrt[i+L]=trans(mul(iGrt[i],iw));
}
}
}
template<int A,int B,int C=0,class fun>inline void Butterrep(int i,int j,int k,fun F){
if(A!=C)F(i,j+C/B,k+C*2-C%B),Butterrep<A,B,C+(C<A)>(i,j,k,F);
}
template<int i,class fun>inline void Butter(int n,fun F){
if(n>32)for(int j=0;2*i*j<n;j+=32/i)Butterrep<32,i>(i,j,2*i*j,F);
else if(i<n)for(int j=0;2*i*j<n;++j)for(int k=0;k<i;++k)F(i,j,k+2*i*j);
}
template<class T>inline void DFT(T P,int n){
extend(n);
const auto F=[&](int x,int y,int z){const int a=P[z],b=mul(P[z+x],Grt[y]);P[z]=add(a,b),P[z+x]=sub(a,b);};
for(int i=n>>1;i>16;i>>=1)for(int j=0;2*i*j<n;++j)for(int k=0;k<i;k+=32)Butterrep<32,32>(i,j,k+2*i*j,F);
Butter<16>(n,F),Butter<8>(n,F),Butter<4>(n,F),Butter<2>(n,F),Butter<1>(n,F);
}
template<class T>inline void IDFT(T P,int n){
const uLL ni=trans(Mod-(Mod-1)/n);
for(int i=0;i<n;++i)P[i]=mul(P[i],ni);
extend(n);
const auto F=[&](int x,int y,int z){const int a=P[z],b=P[z+x];P[z]=add(a,b),P[z+x]=mul(a-b+Mod,iGrt[y]);};
Butter<1>(n,F),Butter<2>(n,F),Butter<4>(n,F),Butter<8>(n,F),Butter<16>(n,F);
for(int i=32;i<n;i<<=1)for(int j=0;2*i*j<n;++j)for(int k=0;k<i;k+=32)Butterrep<32,32>(i,j,k+2*i*j,F);
}
template<class T>inline void rDFT(T P,int n){
extend(n);
const auto F=[&](int x,int y,int z){const int a=P[z],b=mul(P[z+x],Grt[y]);P[z]=add(a,b),P[z+x]=sub(a,b);};
for(int i=n>>1,t=1;i;i>>=1,t<<=1)for(int j=0;2*i*j<n;++j)for(int k=0;k<i;++k)F(i,j+t,k+2*i*j);
}
template<class T>inline void rIDFT(T P,int n){
const uLL ni=trans(Mod-(Mod-1)/n);
for(int i=0;i<n;++i)P[i]=mul(P[i],ni);
extend(n);
const auto F=[&](int x,int y,int z){const int a=P[z],b=P[z+x];P[z]=add(a,b),P[z+x]=mul(a-b+Mod,iGrt[y]);};
for(int i=1,t=n>>1;i<n;i<<=1,t>>=1)for(int j=0;2*i*j<n;++j)for(int k=0;k<i;++k)F(i,j+t,k+2*i*j);
}
inline void DFT(poly&P){DFT(P.begin(),P.size());}
inline void IDFT(poly&P){IDFT(P.begin(),P.size());}
inline void rDFT(poly&P){rDFT(P.begin(),P.size());}
inline void rIDFT(poly&P){rIDFT(P.begin(),P.size());}
inline poly Mul(poly P,poly Q){
if(P.empty()||Q.empty())return poly();
const int pn=P.size(),qn=Q.size(),rn=pn+qn-1;
if(min(pn,qn)<=32||max(pn,qn)<=64){
if(pn<=qn){
vector<uLL>H(rn);
for(int i=0;i<pn;++i){
if(i%8==0)for(int j=qn;j--;)(H[i+j]+=1ll*P[i]*Q[j])>=(Mod2<<3)&&(H[i+j]-=Mod2<<3);
else for(int j=qn;j--;)H[i+j]+=1ll*P[i]*Q[j];
}
Q.resize(rn);
for(int i=rn;i--;)Q[i]=H[i]%Mod;
return Q;
}
else{
vector<uLL>H(rn);
for(int i=0;i<qn;++i){
if(i%8==0)for(int j=pn;j--;)(H[i+j]+=1ll*Q[i]*P[j])>=(Mod2<<3)&&(H[i+j]-=Mod2<<3);
else for(int j=pn;j--;)H[i+j]+=1ll*Q[i]*P[j];
}
P.resize(rn);
for(int i=rn;i--;)P[i]=H[i]%Mod;
return P;
}
}
if(rn<=256){
const int k=max(pn,qn)/2;
poly A=(k<pn?poly(P.begin()+k,P.end()):poly());
poly B=(k<pn?poly(P.begin(),P.begin()+k):P);
poly C=(k<qn?poly(Q.begin()+k,Q.end()):poly());
poly D=(k<qn?poly(Q.begin(),Q.begin()+k):Q);
poly AC=Mul(A,C),BD=Mul(B,D),H=Sub(Mul(Add(A,B),Add(C,D)),Add(AC,BD));
AC.insert(AC.begin(),k*2,0),H.insert(H.begin(),k,0);
H=Add(AC,Add(H,BD));
return H.resize(rn),H;
}
const int m=2<<__lg(max(1,rn-1));
P.resize(m),Q.resize(m);
DFT(P),DFT(Q);
for(int i=m;i--;)P[i]=(LL)P[i]*Q[i]%Mod;
IDFT(P);
return P.resize(rn),P;
}
inline poly MulT(poly P,poly Q){
if(P.empty()||Q.empty())return poly();
reverse(Q.begin(),Q.end());
const int pn=P.size(),qn=Q.size(),m=2<<__lg(max(1,pn-1));
P.resize(m),Q.resize(m);
DFT(P),DFT(Q);
for(int i=m;i--;)P[i]=(LL)P[i]*Q[i]%Mod;
IDFT(P);
return poly(P.begin()+qn-1,P.begin()+pn);
}
inline poly Inv(poly P){
const int pn=P.size();
const int m=2<<__lg(max(1,pn-1));
P.resize(m);
poly Q({qpow(P[0],Mod-2)}),F,dQ;
Q.reserve(m);
for(int n=1;n<m;n*=2){
F=poly(P.begin(),P.begin()+n*2),dQ=Q;
dQ.resize(n*2),DFT(dQ),DFT(F);
for(int i=0;i<n*2;++i)F[i]=(LL)(Mod-F[i])*dQ[i]%Mod;
IDFT(F),fill_n(F.begin(),n,0),DFT(F);
for(int i=0;i<n*2;++i)dQ[i]=(LL)F[i]*dQ[i]%Mod;
IDFT(dQ),Q.insert(Q.end(),dQ.begin()+n,dQ.end());
}
return Q.resize(pn),Q;
}
inline poly Quo(poly F,poly P){
const int pn=P.size();
if(pn<=64){
const uLL r=trans(qpow(P[0],Mod-2));
for(int i=0;i<pn;++i){
LLL v=F[i];
for(int j=0;j<i;++j)v-=(LLL)F[j]*P[i-j];
if((F[i]=v%Mod)<0)F[i]+=Mod;
F[i]=mul(F[i],r);
}
return F;
}
const int m=2<<__lg(max(1,(pn-1)/16)),L=(pn-1)/m+1;
P.resize(m*L),F.resize(m*L);
poly H(F.begin(),F.begin()+m),Q=Inv(poly(P.begin(),P.begin()+m));
vector<poly>A(L),B(L-1);
Q.resize(m*2),H.resize(m*2),DFT(Q),DFT(H);
for(int i=0;i<m*2;++i)H[i]=(LL)H[i]*Q[i]%Mod;
IDFT(H),H.resize(m);
A[0]=poly(P.begin(),P.begin()+m),A[0].resize(m*2),DFT(A[0]);
for(int k=1;k<L;++k){
A[k]=poly(P.begin()+k*m,P.begin()+(k+1)*m),A[k].resize(m*2),DFT(A[k]);
B[k-1]=poly(H.begin()+(k-1)*m,H.begin()+k*m),B[k-1].resize(m*2),DFT(B[k-1]);
poly C(m*2);
for(int j=0;j<k;++j){
for(int i=0;i<m;++i)C[i]=(C[i]+(LL)(A[k-j][i]+A[k-1-j][i])*(Mod-B[j][i]))%Mod;
for(int i=m;i<m*2;++i)C[i]=(C[i]+(LL)(A[k-j][i]+Mod-A[k-1-j][i])*(Mod-B[j][i]))%Mod;
}
IDFT(C),fill_n(C.begin()+m,m,0),C=Add(C,poly(F.begin()+k*m,F.begin()+(k+1)*m)),DFT(C);
for(int i=0;i<m*2;++i)C[i]=(LL)C[i]*Q[i]%Mod;
IDFT(C),H.insert(H.end(),C.begin(),C.begin()+m);
}
return H.resize(pn),H;
}
inline int Sqrt(const int&n){
if(qpow(n,(Mod-1)/2)!=1)return -1;
int a=1;
while(qpow(((LL)a*a+Mod-n)%Mod,(Mod-1)/2)==1)
a=uniform_int_distribution<int>(0,Mod-1)(rng);
const int b=((LL)a*a+Mod-n)%Mod;
pair<int,int>z(1,0),r(a,1);
const auto mul=[&](pair<int,int>x,pair<int,int>y){
return make_pair(((LL)x.first*y.first+(LL)x.second*y.second%Mod*b)%Mod,((LL)x.first*y.second+(LL)x.second*y.first)%Mod);
};
for(int y=(Mod+1)/2;y;(y>>=1)&&(r=mul(r,r),1))if(y&1)z=mul(z,r);
if(z.first<0)z.first+=Mod;
return min(z.first,Mod-z.first);
}
inline poly Sqrt(poly P){
if(P[0]!=1){
const int n=P.size();
int p=0;while(p<n&&!P[p])++p;
if(p>=n)return P;
if(p&1)return poly({-1});
const int v=Sqrt(P[p]);
if(v==-1)return poly({-1});
P.erase(P.begin(),P.begin()+p),P.resize(n-p/2);
P=Mulx(Sqrt(Mulx(P,qpow(P[0],Mod-2))),v);
return P.insert(P.begin(),p/2,0),P;
}
const int pn=P.size();
const int m=2<<__lg(max(1,pn-1));
P.resize(m);
poly Q({1}),H({1}),dQ({Q[0]}),dH,nH;
Q.reserve(m),H.reserve(m),dQ.reserve(m);
for(int n=1;n<m;n*=2){
dH=H;
for(int i=0;i<n;++i)dQ[i]=(LL)dQ[i]*dQ[i]%Mod;
IDFT(dQ),dQ=Sub(Sub(dQ,poly(P.begin(),P.begin()+n)),poly(P.begin()+n,P.begin()+n*2));
dQ.resize(n*2),dH.resize(n*2),DFT(dH),DFT(dQ);
for(int i=0;i<n*2;++i)dQ[i]=div2((LL)(Mod-dQ[i])*dH[i]%Mod);
IDFT(dQ);
Q.insert(Q.end(),dQ.begin(),dQ.begin()+n);
if(n*2==m)break;
dQ=Q,DFT(dQ);
nH.resize(n*2);
for(int i=0;i<n*2;++i)nH[i]=(LL)(Mod-dQ[i])*dH[i]%Mod;
IDFT(nH),fill_n(nH.begin(),n,0),DFT(nH);
for(int i=0;i<n*2;++i)dH[i]=(LL)nH[i]*dH[i]%Mod;
IDFT(dH),H.insert(H.end(),dH.begin()+n,dH.end());
}
return Q.resize(pn),Q;
}
inline poly Sqrti(poly P){
const int v=Sqrt(P[0]);
if(v==-1)return poly({-1});
const int pn=P.size();
const int m=2<<__lg(max(1,pn-1));
poly Q({qpow(v,Mod-2)});
for(int n=1;n<m;n*=2){
poly dQ(Q),F(P.begin(),P.begin()+n*2);
dQ.resize(n*4),F.resize(n*4),DFT(F),DFT(dQ);
for(int i=0;i<n*4;++i)dQ[i]=div2((Mod+1-(LL)F[i]*dQ[i]%Mod*dQ[i]%Mod)*dQ[i]%Mod);
IDFT(dQ),Q.insert(Q.end(),dQ.begin()+n,dQ.begin()+n*2);
}
return Q.resize(pn),Q;
}
inline poly Direv(poly P){
const int n=P.size();
for(int i=1;i<n;++i)P[i-1]=(LL)P[i]*i%Mod;
return P.pop_back(),P;
}
inline poly Integ(poly P){
P.emplace_back(0);
const int n=P.size();Init(n);
for(int i=n;--i;)P[i]=(LL)P[i-1]*inv[i]%Mod;
return P[0]=0,P;
}
inline poly Ln(poly P){
const int n=P.size();
poly Q=Direv(P);Q.resize(n),Q=Quo(Q,P);
return Q.resize(n-1),Integ(Q);
}
template<bool op>inline pair<poly,poly>Expi(poly P){
const int pn=P.size();
const int m=2<<__lg(max(1,pn-1));
P.resize(m);
poly Q({1}),H({1}),dQ({1}),nF,nQ,dH,dnF;
Q.reserve(m),H.reserve(m),dQ.reserve(m);
for(int n=1;n<m;n*=2){
nF=Direv(poly(P.begin(),P.begin()+n)),dnF=nF,dnF.resize(n),DFT(dnF),nQ.resize(n);
for(int i=0;i<n;++i)nQ[i]=(LL)dnF[i]*dQ[i]%Mod;
IDFT(nQ),nQ=Sub(Direv(Q),nQ),nQ.insert(nQ.begin(),n,0),swap(nQ[n-1],nQ[n*2-1]);
DFT(nQ),dH=H,dH.resize(n*2),DFT(dH);
for(int i=0;i<n*2;++i)nQ[i]=(LL)nQ[i]*dH[i]%Mod;
IDFT(nQ),copy(nF.begin(),nF.end(),nQ.begin());
nQ=Sub(Integ(nQ),poly(P.begin(),P.begin()+n*2)),nQ.resize(n*2),DFT(nQ);
dQ.insert(dQ.end(),Q.begin(),Q.end()),rDFT(dQ.begin()+n,n);
for(int i=0;i<n*2;++i)nQ[i]=(LL)(Mod-nQ[i])*dQ[i]%Mod;
IDFT(nQ),Q.insert(Q.end(),nQ.begin()+n,nQ.end());
if(!op&&n*2==m)break;
dQ=Q,DFT(dQ);
for(int i=0;i<n*2;++i)nQ[i]=(LL)(Mod-dQ[i])*dH[i]%Mod;
IDFT(nQ),fill_n(nQ.begin(),n,0),DFT(nQ);
for(int i=0;i<n*2;++i)nQ[i]=(LL)nQ[i]*dH[i]%Mod;
IDFT(nQ),H.insert(H.end(),nQ.begin()+n,nQ.end());
}
return Q.resize(pn),H.resize(pn),make_pair(Q,H);
}
inline poly Exp(poly P){
const int pn=P.size();
if(pn<=64)return Expi<0>(P).first;
const int m=2<<__lg(max(1,(pn-1)/16)),L=(pn-1)/m+1;
auto [Q,H]=Expi<1>(poly(P.begin(),P.begin()+m));
H.resize(m*2),DFT(H);
vector<poly>A(L),B(L-1);
P.resize(m*L),Init(m*(L+1));
for(int i=0;i<pn;++i)P[i]=(LL)P[i]*i%Mod;
A[0]=poly(P.begin(),P.begin()+m),A[0].resize(m*2),DFT(A[0]);
for(int k=1;k<L;++k){
A[k]=poly(P.begin()+k*m,P.begin()+(k+1)*m),A[k].resize(m*2),DFT(A[k]);
B[k-1]=poly(Q.begin()+(k-1)*m,Q.begin()+k*m),B[k-1].resize(m*2),DFT(B[k-1]);
poly C(m*2);
for(int j=0;j<k;++j){
for(int i=0;i<m;++i)C[i]=(C[i]+(LL)(A[k-j][i]+A[k-1-j][i])*B[j][i])%Mod;
for(int i=m;i<m*2;++i)C[i]=(C[i]+(LL)(A[k-j][i]+Mod-A[k-1-j][i])*B[j][i])%Mod;
}
IDFT(C),fill_n(C.begin()+m,m,0),DFT(C);
for(int i=0;i<m*2;++i)C[i]=(LL)C[i]*H[i]%Mod;
IDFT(C),fill_n(C.begin()+m,m,0);
for(int i=0;i<m*2;++i)C[i]=(LL)C[i]*inv[m*k+i]%Mod;
DFT(C);
for(int i=0;i<m*2;++i)C[i]=(LL)C[i]*B[0][i]%Mod;
IDFT(C),Q.insert(Q.end(),C.begin(),C.begin()+m);
}
return Q.resize(pn),Q;
}
inline poly Qpow(poly P,int k){
return Exp(Mulx(Ln(P),k));
}
inline poly SafePow(poly P,int k_mod_p,int k_mod_phi,int k_chk_mn){
const int n=P.size();
int i=0;while(i<n&&!P[i])++i;
if(1ll*i*k_chk_mn>=n)return poly(n);
P=poly(P.begin()+i,P.begin()+i+(n-i*k_chk_mn));
const int r=P[0];P=Mulx(P,qpow(r,Mod-2));
P=Qpow(P,k_mod_p),P=Mulx(P,qpow(r,k_mod_phi));
return P.insert(P.begin(),i*k_chk_mn,0),P;
}
template<class T>inline poly SafePow(poly P,T k){
return SafePow(P,k%Mod,k%(Mod-1),k<P.size()?k:P.size());
}
inline poly Shift(poly P,int k){
if(!k)return P;
const int n=P.size();
Init(n);
for(int i=0;i<n;++i)P[i]=(LL)frc[i]*P[i]%Mod;
poly Q(n,1);
for(int i=1;i<n;++i)Q[i]=(LL)Q[i-1]*k%Mod*inv[i]%Mod;
P.resize(n+n-1),Q=MulT(P,Q);
for(int i=0;i<n;++i)Q[i]=(LL)Q[i]*ivf[i]%Mod;
return Q;
}
inline poly Multi(poly P,int k){
const uLL v=trans(k);
const int n=P.size();
for(int i=0,w=1;i<n;++i,w=mul(w,v))P[i]=(LL)P[i]*w%Mod;
return P;
}
inline poly ModPow(poly X,LL k,poly P){
const int m=P.size();
poly nP=P;reverse(nP.begin(),nP.end()),nP=Inv(nP);
const int L=2<<__lg(m*2-1);
P.resize(L),nP.resize(L),DFT(P),DFT(nP);
int Xn=X.size();
X.resize(L),DFT(X);
const auto MoD=[&](poly F){
poly nF=F;
IDFT(nF);
nF.resize(m*2-3),reverse(nF.begin(),nF.end()),nF.resize(m-2);
nF.resize(L),DFT(nF);
for(int i=0;i<L;++i)nF[i]=(LL)nF[i]*nP[i]%Mod;
IDFT(nF),nF.resize(m-2),reverse(nF.begin(),nF.end());
nF.resize(L),DFT(nF);
for(int i=0;i<L;++i)nF[i]=(LL)nF[i]*P[i]%Mod;
return Sub(F,nF);
};
poly Q({1});
int Qn=Q.size();
Q.resize(L),DFT(Q);
while(k){
if(k&1){
for(int i=0;i<L;++i)Q[i]=(LL)Q[i]*X[i]%Mod;
Qn+=Xn-1;
if(Qn>=m)Q=MoD(Q),Qn=m-1;
}
if(k>>=1){
for(int i=0;i<L;++i)X[i]=(LL)X[i]*X[i]%Mod;
Xn+=Xn-1;
if(Xn>=m)X=MoD(X),Xn=m-1;
}
}
return IDFT(Q),Q.resize(m-1),Q;
}
inline poly Comp_solve(poly&P,poly&Q,int d,int n,int v){
if(n==1){
poly H(d+1);
for(int i=0,w=1;i<=d;++i)
H[i]=(LL)Binom(d+i-1,d-1)*w%Mod,w=(LL)w*v%Mod;
H=MulT(P,H);
return H;
}
poly F(d*n*4);
for(int i=0;i<d;++i)copy_n(Q.begin()+i*n,n,F.begin()+i*n*2);
F[d*n*2]=1,DFT(F);
poly H(d*n*2);
for(int i=0;i<d*n*4;i+=2)H[i/2]=(LL)F[i]*F[i+1]%Mod;
IDFT(H),--H[0];
for(int i=1;i<d*2;++i)copy_n(H.begin()+i*n,n/2,H.begin()+i*(n/2));
H.resize(d*n);
H=Comp_solve(P,H,d*2,n/2,v);
poly nH(d*n*2);
for(int i=0;i<d*2;++i)copy_n(H.begin()+i*(n/2),n/2,nH.begin()+i*n);
DFT(nH);
for(int i=0;i<d*n*4;i+=2)swap(F[i],F[i+1]),F[i]=(LL)nH[i/2]*F[i]%Mod,F[i+1]=(LL)nH[i/2]*F[i+1]%Mod;
IDFT(F);
for(int i=0;i<d;++i)copy_n(F.begin()+(i+d)*n*2,n,F.begin()+i*n);
return F.resize(d*n),F;
}
inline poly Comp(poly P,poly Q){
if(P.empty()||Q.empty())return poly();
const int pn=P.size(),m=2<<__lg(max(1,pn-1)),v=Q[0];
P.resize(m+m),Q=Neg(Q),Q.resize(m);
Q=Comp_solve(P,Q,1,m,v);
return Q.resize(pn),Q;
}
poly Compinv(poly P){
const int n=P.size(),t=qpow(P[1],Mod-2);
for(int i=1,w=t;i<n;++i)P[i]=(LL)P[i]*w%Mod,w=(LL)w*t%Mod;
const int m=2<<__lg(n-1);
poly Q(m);Q[0]=1,P=Neg(P),P.resize(m);
P.swap(Q);
int d=1;
for(int k=n-1;k;d*=2,k/=2){
const int L=2<<__lg(d*(k+1)*4-1);
poly nP(L),nQ(L);
for(int i=0;i<d;++i)
copy_n(P.begin()+i*(k+1),k+1,nP.begin()+i*(k+1)*2),
copy_n(Q.begin()+i*(k+1),k+1,nQ.begin()+i*(k+1)*2);
nQ[d*(k+1)*2]=1,DFT(nP),DFT(nQ);
P.resize(L/2),Q.resize(L/2);
if(k&1)for(int i=0;i<L;i+=2)
P[i/2]=div2(mul(((LL)nP[i]*nQ[i+1]+(LL)(Mod-nP[i+1])*nQ[i])%Mod,iGrt[i/2])),Q[i/2]=(LL)nQ[i]*nQ[i+1]%Mod;
else for(int i=0;i<L;i+=2)
P[i/2]=div2(((LL)nP[i]*nQ[i+1]+(LL)nP[i+1]*nQ[i])%Mod),Q[i/2]=(LL)nQ[i]*nQ[i+1]%Mod;
IDFT(P),IDFT(Q);
if(d*(k+1)*4>=L)--Q[d*(k+1)*4%L];
for(int i=1;i<d*2;++i)
copy_n(P.begin()+i*(k+1),k/2+1,P.begin()+i*(k/2+1)),
copy_n(Q.begin()+i*(k+1),k/2+1,Q.begin()+i*(k/2+1));
P.resize(d*2*(k/2+1)),Q.resize(d*2*(k/2+1));
}
Init(n);
Q=P,reverse(Q.begin(),Q.end()),Q.resize(n);
for(int i=1;i<n;++i)Q[i]=Q[i]*(n-1ll)%Mod*inv[i]%Mod;
reverse(Q.begin(),Q.end()),Q=Mulx(Qpow(Q,Mod-inv[n-1]),t),Q.insert(Q.begin(),0);
return Q.resize(n),Q;
}
inline poly Div(poly P,poly Q){
const int n=P.size(),m=Q.size();
if(n<m)return poly();
reverse(P.begin(),P.end());
reverse(Q.begin(),Q.end());
P.resize(n-m+1),Q.resize(n-m+1);
P=Quo(P,Q),reverse(P.begin(),P.end());
return P;
}
inline pair<poly,poly>DivMod(poly P,poly Q){
if(P.size()<Q.size())return make_pair(poly(),P);
const int m=Q.size();
poly H=Div(P,Q),R=H;
P.resize(m-1),Q.resize(m-1);
if((int)R.size()>m-1)R.resize(m-1);
Q=Mul(Q,R),Q.resize(m-1);
return make_pair(H,Sub_Empty(P,Q));
}
inline vector<poly>_EIBuild(poly Q){
const int n=Q.size(),lgm=__lg(max(1,n-1))+1,m=1<<lgm;
vector<poly>T(lgm+1,poly(m*2));
Q.resize(m);
for(int i=0;i<m;++i)T[0][i*2]=Mod+1-Q[i],T[0][i*2+1]=Mod-1-Q[i];
for(int d=0,i=2;d<lgm;++d,i*=2){
poly A(i);
for(int j=0;j<m*2;j+=i*2){
for(int k=0;k<i;++k)A[k]=(LL)T[d][j+k]*T[d][j+i+k]%Mod;
if(d<lgm-1)copy_n(A.begin(),i,T[d+1].begin()+j),IDFT(A),A[0]=sub(A[0],2),rDFT(A),copy_n(A.begin(),i,T[d+1].begin()+j+i);
else IDFT(A),copy_n(A.begin(),i,T[d+1].begin()+j),T[d+1][j]=sub(T[d+1][j],1),T[d+1][i]=add(T[d+1][i],1);
}
}
return T;
}
inline poly _Eval(poly P,int n,vector<poly>T){
const int pn=P.size(),lgm=T.size()-1,m=1<<lgm;
poly Q=T[lgm];
if(pn>n)P=DivMod(P,poly(T[lgm].begin()+m-n,T[lgm].begin()+m+1)).second;
P.resize(m*2),rotate(P.begin(),P.end()-1,P.end());
reverse(Q.begin(),Q.begin()+m+1),Q.resize(m),Q=Inv(Q);
reverse(Q.begin(),Q.end()),Q.resize(m*2),DFT(P),DFT(Q);
for(int i=0;i<m*2;++i)Q[i]=(LL)P[i]*Q[i]%Mod;
for(int d=lgm,i=m;d--;i>>=1){
poly A(i);
for(int j=0;j<m*2;j+=i*2){
copy_n(Q.begin()+i+j,i,A.begin());
rIDFT(A),DFT(A),copy_n(A.begin(),i,Q.begin()+i+j);
for(int k=0;k<i;++k){
const int w=sub(Q[j+k],Q[i+j+k]);
Q[j+k]=(LL)w*T[d][i+j+k]%Mod,Q[i+j+k]=(LL)w*T[d][j+k]%Mod;
}
}
}
const int ni=Mod-(Mod-1)/(m+m);
for(int i=0;i<n;++i)P[i]=(LL)(Q[i*2]-Q[i*2+1]+Mod)*ni%Mod;
return P.resize(n),P;
}
inline poly Eval(poly P,poly Q){
return _Eval(P,Q.size(),_EIBuild(Q));
}
inline poly Inter(poly P,poly Q){
const int n=P.size();
vector<poly>T=_EIBuild(P);
const int lgm=T.size()-1,m=1<<lgm;
P=T[lgm],P.erase(P.begin(),P.begin()+m-n),P=invLinear(_Eval(Direv(P),n,T));
P.resize(m+m),Q.resize(m+m);
for(int i=m;i--;)P[i*2]=P[i*2+1]=(LL)Q[i]*P[i]%Mod;
for(int d=0,i=2;d<lgm;++d,i*=2,swap(P,Q)){
poly A(i);
for(int j=0;j<m+m;j+=i*2){
for(int k=0;k<i;++k)A[k]=((LL)T[d][j+k]*P[j+i+k]+(LL)T[d][j+i+k]*P[j+k])%Mod;
if(d<lgm-1)copy_n(A.begin(),i,Q.begin()+j),IDFT(A),rDFT(A),copy_n(A.begin(),i,Q.begin()+j+i);
else IDFT(A),copy_n(A.begin(),i,Q.begin());
}
}
return poly(P.begin()+m-n,P.begin()+m);
}
inline poly ChirpZ(poly P,int X,int m){
if(!X){
poly Q(m,Eval(P,0));
return Q[0]=Eval(P,1),Q;
}
const int n=P.size();
const uLL x=trans(X),y=trans(qpow(X,Mod-2));
int pwX=1,ipwX=1;
poly pwXX(n+m-1,1),ipwXX(n+m-1,1);
for(int i=0;i+1<n+m;++i)
pwXX[i+1]=(LL)pwXX[i]*pwX%Mod,ipwXX[i+1]=(LL)ipwXX[i]*ipwX%Mod,pwX=mul(pwX,x),ipwX=mul(ipwX,y);
for(int i=0;i<n;++i)P[i]=(LL)P[i]*ipwXX[i]%Mod;
P=MulT(pwXX,P);
for(int i=0;i<m;++i)P[i]=(LL)P[i]*ipwXX[i]%Mod;
return P;
}
inline poly ChirpZInter(poly P,int X){
const int n=P.size();
if(n<2)return P;
const uLL x=trans(X),y=trans(qpow(X,Mod-2));
poly pwXX(n+n-1,1),ipwXX(n+n-1,1);
int pwX=1,ipwX=1;
for(int i=0;i+1<n+n;++i)
pwXX[i+1]=(LL)pwXX[i]*pwX%Mod,ipwXX[i+1]=(LL)ipwXX[i]*ipwX%Mod,pwX=mul(pwX,x),ipwX=mul(ipwX,y);
poly Q(n,1);
int t=X;
for(int i=1;i<n;++i)Q[i]=(LL)(Mod+1-t)*Q[i-1]%Mod,t=mul(t,x);
t=(LL)(Mod+1-t)*Q[n-1]%Mod;
Q=invLinear(Q);
for(int i=0;i<n;++i)
P[i]=(LL)(i&1?Mod-P[i]:P[i])*pwXX[n-1-i]%Mod*ipwXX[n-1]%Mod*Q[i]%Mod*Q[n-1-i]%Mod*ipwXX[i]%Mod;
P=MulT(pwXX,P);
for(int i=0;i<n;++i)P[i]=(LL)P[i]*ipwXX[i]%Mod;
poly H(n,1);
for(int i=1;i<n;++i)
H[i]=(LL)(i&1?Mod-t:t)*pwXX[i]%Mod*Q[i]%Mod*Q[n-i]%Mod;
P=Mul(P,H),P.resize(n),reverse(P.begin(),P.end());
return P;
}
inline poly PointShift(poly P,int l,int r){
const int n=P.size();Init(n);
if(l<n){
if(r<n)return poly(P.begin()+l,P.begin()+r+1);
else{
poly Q=PointShift(P,n,r);
Q.insert(Q.begin(),P.begin()+l,P.end());
return Q;
}
}
if(r>=Mod){
r-=Mod;
poly Q=PointShift(P,l,Mod-1);
if(r<n)Q.insert(Q.end(),P.begin(),P.begin()+r+1);
else Q.insert(Q.end(),P.begin(),P.end()),P=PointShift(P,n,r),Q.insert(Q.end(),P.begin(),P.end());
return Q;
}
poly Q(r-l+n),H(n);
for(int i=0;i<n;++i)H[i]=(LL)((n-1-i)&1?Mod-P[i]:P[i])*ivf[i]%Mod*ivf[n-1-i]%Mod;
for(int i=0;i<r-l+n;++i)Q[i]=l-n+i+1;
Q=invLinear(Q),reverse(H.begin(),H.end()),Q=MulT(Q,H);
poly fac(r-l+1+n);
fac[0]=1;
for(int i=0;i<r-l+n;++i)fac[i+1]=max(1ll,(LL)fac[i]*(l+i-n+1)%Mod);
poly ifac=invLinear(fac);
for(int i=0;i<=r-l;++i){
const int p=(i+l)%Mod;
if(p>=0&&p<n)Q[i]=P[p];
else Q[i]=(LL)Q[i]*ifac[i]%Mod*fac[i+n]%Mod;
}
return Q;
}
inline Mat2 operator*(const Mat2&x,const Mat2&y){
return Mat2(
Add_Empty(Mul(get<0>(x),get<0>(y)),Mul(get<1>(x),get<2>(y))),
Add_Empty(Mul(get<0>(x),get<1>(y)),Mul(get<1>(x),get<3>(y))),
Add_Empty(Mul(get<2>(x),get<0>(y)),Mul(get<3>(x),get<2>(y))),
Add_Empty(Mul(get<2>(x),get<1>(y)),Mul(get<3>(x),get<3>(y)))
);
}
inline Mat2 Hgcd(poly P,poly Q,int d){
if(P.size()<Q.size())return Hgcd(Q,P,d)*Mat2(poly(),poly({1}),poly({1}),poly());
d=min(d,(int)P.size()-1);
if(Q.empty()||Q.size()<P.size()-d)return Mat2(poly({1}),poly(),poly(),poly({1}));
const int m=P.size()-d*2-1;
if(m>0)P=poly(P.begin()+m,P.end()),Q=poly(Q.begin()+m,Q.end());
if(!d)return Mat2(poly(),poly({1}),poly({1}),Neg(Div(P,Q)));
const Mat2 M=Hgcd(P,Q,d/2);
const poly H=Add_Empty(Mul(get<2>(M),P),Mul(get<3>(M),Q));
if(H.size()<P.size()-d)return M;
const poly R=Add_Empty(Mul(get<0>(M),P),Mul(get<1>(M),Q));
const auto [A,B]=DivMod(R,H);
return Hgcd(H,B,H.size()-P.size()+d)*Mat2(poly(),poly({1}),poly({1}),Neg(A))*M;
}
inline tuple<poly,poly,poly>Exgcd(poly P,poly Q){
Empty(P),Empty(Q);
const Mat2 M=Hgcd(P,Q,max(P.size(),Q.size())-1);
const poly H=Add_Empty(Mul(get<0>(M),P),Mul(get<1>(M),Q));
const int v=qpow(H.back(),Mod-2);
return make_tuple(Mulx(get<0>(M),v),Mulx(get<1>(M),v),Mulx(H,v));
}
inline poly Gcd(poly P,poly Q){
return get<2>(Exgcd(P,Q));
}
inline poly Modinv(poly P,poly Q){
const auto [W,_,D]=Exgcd(P,Q);
return D.size()>1?poly({-1}):W;
}
inline poly operator*(poly P,poly Q){return Mul(P,Q);}
inline poly operator*(poly P,int x){return Mulx(P,x);}
inline poly operator*(int x,poly P){return Mulx(P,x);}
inline poly operator+(poly P,poly Q){return Add(P,Q);}
inline poly operator-(poly P,poly Q){return Sub(P,Q);}
inline poly operator-(poly P){return Neg(P);}
inline poly operator/(poly P,poly Q){return Div(P,Q);}
inline poly operator%(poly P,poly Q){return DivMod(P,Q).second;}
inline poly&operator*=(poly&P,poly Q){return P=Mul(P,Q);}
inline poly&operator*=(poly&P,int x){return P=Mulx(P,x);}
inline poly&operator+=(poly&P,poly Q){return P=Add(P,Q);}
inline poly&operator-=(poly&P,poly Q){return P=Sub(P,Q);}
inline poly&operator/=(poly&P,poly Q){return P=Div(P,Q);}
inline poly&operator%=(poly&P,poly Q){return P=DivMod(P,Q).second;}
int main()
{
cin.tie(0)->sync_with_stdio(0);
int n;cin>>n;
poly f(n),g(n);
g[1]=1;
for(int i=0;i<n;i++)cin>>f[i];
int b=(Mod+1)/2;
while(b)
{
if(b&1)g=Comp(g,f);
f=Comp(f,f),b/=2;
}
for(int i=0;i<n;i++)printf("%d ",g[i]);
}
提出情報
提出日時
2025-11-06 09:12:00+0900
問題
X - 関数的平方根
ユーザ
gjzxjp
言語
C++ 20 (gcc 12.2)
得点
1
コード長
25401 Byte
結果
AC
実行時間
477 ms
メモリ
7088 KiB
コンパイルエラー
Main.cpp: In function ‘int qpow(int, int, int)’:
Main.cpp:22:9: warning: this ‘for’ clause does not guard... [-Wmisleading-indentation]
22 | for(;y;(y>>=1)&&(x=(LL)x*x%Mod))if(y&1)z=(LL)z*x%Mod;return z;
| ^~~
Main.cpp:22:62: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the ‘for’
22 | for(;y;(y>>=1)&&(x=(LL)x*x%Mod))if(y&1)z=(LL)z*x%Mod;return z;
| ^~~~~~
ジャッジ結果
セット名
Sample
All
得点 / 配点
0 / 0
1 / 1
結果
セット名
テストケース
Sample
00_sample_00.txt, 00_sample_01.txt
All
00_sample_00.txt, 00_sample_01.txt, 01_random_00.txt, 01_random_01.txt, 02_min_00.txt, 03_max_00.txt, 04_corner_00.txt
ケース名
結果
実行時間
メモリ
00_sample_00.txt
AC
1 ms
3900 KiB
00_sample_01.txt
AC
1 ms
3924 KiB
01_random_00.txt
AC
476 ms
7000 KiB
01_random_01.txt
AC
477 ms
7088 KiB
02_min_00.txt
AC
1 ms
3892 KiB
03_max_00.txt
AC
473 ms
6956 KiB
04_corner_00.txt
AC
476 ms
6944 KiB