P5748-集合劃分計數【EGF,多項式exp】
阿新 • • 發佈:2021-06-30
正題
題目連結:https://www.luogu.com.cn/problem/P5748
題目大意
求將\(n\)的排列分成若干個無序非空集合的方案。
輸出答案對\(998244353\)取模。
\(1\leq n\leq 10^5,1\leq T\leq 1000\)
解題思路
分成\(i\)個集合的方案是\((e^x-1)^i\)所以答案的生成函式就是
\[\sum_{i=0}^{\infty}\frac{(e^x-1)^i}{i!} \]emmmmmmmmmmm...
怎麼看上去這麼眼熟,所以
然後寫個多項式exp就好了
時間複雜度\(O(n\log n)\)
code
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=8e5+10,P=998244353; ll T,n,f[N],g[N],r[N]; ll t1[N],t2[N],t3[N],t4[N],t5[N],t6[N]; ll power(ll x,ll b){ ll ans=1; while(b){ if(b&1)ans=ans*x%P; x=x*x%P;b>>=1; } return ans; } void GetL(ll l){ n=1;while(n<=l)n<<=1; for(ll i=0;i<n;i++) r[i]=(r[i>>1]>>1)|((i&1)?(n>>1):0); return; } void NTT(ll *f,ll op){ for(ll i=0;i<n;i++) if(i<r[i])swap(f[i],f[r[i]]); for(ll p=2;p<=n;p<<=1){ ll len=p>>1,tmp=power(3,(P-1)/p); if(op==-1)tmp=power(tmp,P-2); for(ll k=0;k<n;k+=p){ ll buf=1; for(ll i=k;i<k+len;i++){ ll tt=f[i+len]*buf%P; f[i+len]=(f[i]-tt+P)%P; f[i]=(f[i]+tt)%P; buf=buf*tmp%P; } } } if(op==-1){ ll invn=power(n,P-2); for(ll i=0;i<n;i++) f[i]=f[i]*invn%P; } return; } void GetInv(ll *f,ll *g,ll m){ if(m==1){g[0]=power(f[0],P-2);return;} GetInv(f,g,m>>1);GetL(m); for(ll i=0;i<m;i++)t1[i]=g[i],t2[i]=f[i]; NTT(t1,1);NTT(t2,1); for(ll i=0;i<n;i++) t1[i]=t1[i]*t1[i]%P*t2[i]%P; NTT(t1,-1); for(ll i=0;i<m;i++) g[i]=(2*g[i]-t1[i]+P)%P; for(ll i=0;i<n;i++)t1[i]=t2[i]=0; return; } void GetD(ll *f,ll *g,ll m){ for(ll i=0;i<m-1;i++) g[i]=f[i+1]*(i+1)%P; g[m-1]=0;return; } void GetJ(ll *f,ll *g,ll m){ for(ll i=1;i<m;i++) g[i]=f[i-1]*power(i,P-2)%P; g[0]=0;return; } void GetLn(ll *f,ll *g,ll m){ GetD(f,t3,m);GetInv(f,t4,m); GetL(m);NTT(t3,1);NTT(t4,1); for(ll i=0;i<n;i++)t3[i]=t3[i]*t4[i]%P; NTT(t3,-1);GetJ(t3,g,n); for(ll i=0;i<n;i++)t3[i]=t4[i]=0; for(ll i=m;i<n;i++)g[i]=0; return; } void GetExp(ll *f,ll *g,ll m){ if(m==1){g[0]=1;return;} GetExp(f,g,m>>1);GetLn(g,t5,m); for(ll i=0;i<m;i++)t6[i]=f[i]; GetL(m);NTT(t5,1);NTT(t6,1);NTT(g,1); for(ll i=0;i<n;i++) g[i]=g[i]*(1-t5[i]+t6[i]+P)%P; NTT(g,-1);for(ll i=m;i<n;i++)g[i]=0; for(ll i=0;i<n;i++)t5[i]=t6[i]=0; return; } signed main() { ll m=1;while(m<=1e5)m<<=1; f[1]=1;GetExp(f,g,m); (g[0]+=P-1)%=P;f[1]=0; GetExp(g,f,m); for(ll i=1,F=1;i<=m;i++,F=F*i%P)f[i]=f[i]*F%P; scanf("%lld",&T); while(T--){ scanf("%lld",&n); printf("%lld\n",f[n]); } return 0; }