\(\text{Problem}:\)第二类斯特林数·列
\(\text{Solution}:\)
首先推导一下多项式求逆:
设多项式 \(A\) 模 \(x^{n}\) 逆元为 \(B\),模 \(x^{\lceil \frac{n}{2}\rceil}\) 逆元为 \(B'\),有:
\[A\times B\equiv 1\pmod {x^{\lceil \frac{n}{2}\rceil}}\\ A\times B'\equiv 1\pmod {x^{\lceil \frac{n}{2}\rceil}}\\ B'-B\equiv 0 \pmod{x^{\lceil \frac{n}{2}\rceil}} \]两边平方,得到:
\[B'^{2}-2BB'+B^{2}\equiv 0 \pmod {x^{n}} \]两边同乘 \(A\),得到:
\[AB'^{2}-2B'+B\equiv 0 \pmod {x^{n}}\\ B\equiv 2B'-AB'^{2} \pmod {x^{n}} \]这样就可以递归求出 \(B\),用 \(\text{NTT}\) 优化多项式乘法即可做到 \(O(n\log n)\)。
设第 \(k\) 列第二类斯特林数的 \(\text{OGF}\) 为 \(F_{k}(x)=\sum\limits_{i=0}^{\infty}{i\brace k}x^{i}\),则有:
\[\begin{aligned} F_{k}(x)&=\sum\limits_{i=0}^{\infty}\left(k{i-1\brace k}+{i-1\brace k-1}\right)x^{i}\\ &=k\sum\limits_{i=0}^{\infty}{i-1\brace k}x^{i}+\sum\limits_{i=0}^{\infty}{i-1\brace k-1}x^{i}\\ &=kx\sum\limits_{i=0}^{\infty}{i\brace k}x^{i}+x\sum\limits_{i=0}^{\infty}{i\brace k-1}x^{i}\\ &=kxF_{k}(x)+xF_{k-1}(x)\\ F_{k}(x)&=\cfrac{x}{1-kx}F_{k-1}(x) \end{aligned} \]易知 \(F_{0}(x)=1\),得到:
\[F_{k}(x)=\cfrac{x^{k}}{\prod_{i=1}^{k}(1-ix)} \]利用分治乘法求出分母,求逆后再乘上 \(x^{k}\) 就得到答案。时间复杂度 \(O(n\log^2 n)\)。
\(\text{Code}:\)
#include <bits/stdc++.h> #pragma GCC optimize(3) //#define int long long #define ri register #define mk make_pair #define fi first #define se second #define pb push_back #define eb emplace_back #define is insert #define es erase #define vi vector<int> #define vpi vector<pair<int,int>> using namespace std; const int N=300010, Mod=167772161; inline int read() { int s=0, w=1; ri char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); } while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar(); return s*w; } int n,K; int rev[N],r[26][2]; vector<int> F,G; inline int ksc(int x,int p) { int res=1; for(;p;p>>=1, x=1ll*x*x%Mod) if(p&1) res=1ll*res*x%Mod; return res; } inline void Get_Rev(int T) { for(ri int i=0;i<T;i++) rev[i]=(rev[i>>1]>>1)|((i&1)?(T>>1):0); } inline void DFT(int T,vector<int> &s,int type) { for(ri int i=0;i<T;i++) if(rev[i]<i) swap(s[i],s[rev[i]]); for(ri int i=2,cnt=1;i<=T;i<<=1,cnt++) { int wn=r[cnt][type]; for(ri int j=0,mid=(i>>1);j<T;j+=i) { for(ri int k=0,w=1;k<mid;k++,w=1ll*w*wn%Mod) { int x=s[j+k], y=1ll*w*s[j+mid+k]%Mod; s[j+k]=(x+y)%Mod; s[j+mid+k]=x-y; if(s[j+mid+k]<0) s[j+mid+k]+=Mod; } } } if(!type) for(ri int i=0,inv=ksc(T,Mod-2);i<T;i++) s[i]=1ll*s[i]*inv%Mod; } inline void NTT(int n,int m,vector<int> &A,vector<int> &B) { int len=n+m; int T=1; while(T<=len) T<<=1; Get_Rev(T); A.resize(T), B.resize(T); for(ri int i=n+1;i<T;i++) A[i]=0; for(ri int i=m+1;i<T;i++) B[i]=0; DFT(T,A,1), DFT(T,B,1); for(ri int i=0;i<T;i++) A[i]=1ll*A[i]*B[i]%Mod; DFT(T,A,0); A.erase(A.begin()+n+m+1,A.end()); B.erase(B.begin()+m+1,B.end()); } void Solve(int l,int r,vector<int> &F) { if(l==r) { F.resize(2); F[0]=1, F[1]=Mod-l; return; } int mid=(l+r)/2; Solve(l,mid,F); vector<int> G; Solve(mid+1,r,G); NTT(F.size()-1,G.size()-1,F,G); } void Inv(int n,vector<int> &G) { if(n==1) { G[0]=ksc(F[0],Mod-2); return; } Inv((n+1)/2,G); vector<int> A,B; int T=1; while(T<=n*2) T<<=1; Get_Rev(T); A.resize(T), B.resize(T); for(ri int i=0;i<n;i++) A[i]=F[i], B[i]=G[i]; DFT(T,A,1), DFT(T,B,1); for(ri int i=0;i<T;i++) B[i]=(2ll*B[i]%Mod-1ll*A[i]*B[i]%Mod*B[i]%Mod+Mod)%Mod; DFT(T,B,0); for(ri int i=0;i<n;i++) G[i]=B[i]; } signed main() { r[25][1]=ksc(3,5), r[25][0]=ksc(ksc(3,Mod-2),5); for(ri int i=24;~i;i--) r[i][0]=1ll*r[i+1][0]*r[i+1][0]%Mod, r[i][1]=1ll*r[i+1][1]*r[i+1][1]%Mod; n=read(), K=read(); if(K>n) { for(ri int i=0;i<=n;i++) printf("0 "); puts(""); return 0; } for(ri int i=0;i<K;i++) printf("0 "); Solve(1,K,F); F.resize(n-K+1), G.resize(n-K+1); Inv(n-K+1,G); for(ri int i=K;i<=n;i++) printf("%d ",G[i-K]); puts(""); return 0; }
后记:本题还有 \(O(n\log n)\) 的 \(\text{EGF}\) 做法,此处不表。