【模板】【洛谷P5409】第一类斯特林数·列(多项式Exp)(多项式快速幂)

传送门


题解:

感觉求这个玩意的方法略迷,记录一下这个清奇的思路。

考虑展开 ( 1 + x ) t (1+x)^t (1+x)t

( 1 + x ) t = ∑ i = 0 ∞ ( t i ) x i = ∑ i = 0 ∞ x i t i ‾ i ! = ∑ i = 0 ∞ x i i ! ∑ j = 0 i [ i j ] ( − 1 ) i − j t j = ∑ j = 0 ∞ t j ∑ i = j ∞ x i i ! [ i j ] ( − 1 ) i − j \begin{aligned} (1+x)^t&=&&\sum_{i=0}^\infty {t\choose i}x^i\\ &=&&\sum_{i=0}^\infty \frac{x^it^{\underline{i}}}{i!}\\ &=&&\sum_{i=0}^\infty \frac{x^i}{i!}\sum_{j=0}^i\begin{bmatrix}i\\j\end{bmatrix}(-1)^{i-j}t^j\\ &=&&\sum_{j=0}^\infty t^j\sum_{i=j}^\infty\frac{x^i}{i!}\begin{bmatrix}i\\j\end{bmatrix}(-1)^{i-j} \end{aligned} (1+x)t====i=0(it)xii=0i!xitii=0i!xij=0i[ij](1)ijtjj=0tji=ji!xi[ij](1)ij

然后考虑 ln ⁡ + exp ⁡ \ln+\exp ln+exp的展开方式。

( 1 + x ) t = exp ⁡ ( t ⋅ ln ⁡ ( 1 + x ) ) = ∑ i = 0 ∞ t i ⋅ ( ln ⁡ ( 1 + x ) ) i i ! \begin{aligned} (1+x)^t&=&&\exp(t\cdot \ln(1+x))\\ &=&&\sum_{i=0}^\infty t^i\cdot \frac{(\ln(1+x))^i}{i!} \end{aligned} (1+x)t==exp(tln(1+x))i=0tii!(ln(1+x))i

前后对比可以得到: ∑ j = i ∞ ( − 1 ) j − i [ j i ] x j i ! = ( ln ⁡ ( 1 + x ) ) i i ! \sum_{j=i}^\infty \frac{(-1)^{j-i}\begin{bmatrix}j\\i\end{bmatrix}x^j}{i!}=\frac{(\ln(1+x))^i}{i!} j=ii!(1)ji[ji]xj=i!(ln(1+x))i

这是一种方法。

然而,我们考虑只有一个循环的置换的EGF:

∑ i = 1 ∞ ( i − 1 ) ! x i i ! = ∑ i = 1 ∞ x i i \sum_{i=1}^{\infty}\frac{(i-1)!x^i}{i!}=\sum_{i=1}^\infty\frac{x^i}{i} i=1i!(i1)!xi=i=1ixi

直接对上面这个东西算K次方就能得到K个环的置换的生成函数。去掉环的排列顺序算上点的排列顺序就行了。

需要比较通用的快速幂板子。

时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)


代码:

#include
#define ll long long
#define re register
#define cs const

using std::cerr;
using std::cout;

cs int mod=167772161;
inline int add(int a,int b){return (a+=b)>=mod?a-mod:a;}
inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
inline int mul(int a,int b){static ll r;r=(ll)a*b;return r>=mod?r%mod:r;}
inline int power(int a,int b,int res=1){
	for(;b;b>>=1,a=mul(a,a))(b&1)&&(res=mul(res,a));
	return res;
}
inline void Inc(int &a,int b){(a+=b)>=mod?a-=mod:0;}
inline void Dec(int &a,int b){(a-=b)<0?a+=mod:0;}
inline void Mul(int &a,int b){a=mul(a,b);}

typedef std::vector<int> Poly;

std::ostream &operator<<(std::ostream &out,cs Poly &a){
	if(!a.size())out<<"empty ";
	else for(int re i:a)out<<i<<" ";
	return out;
}

cs int bit=20,SIZE=1<<20|1;

int r[SIZE],*w[bit+1];
int fac[SIZE],ifac[SIZE],inv[SIZE];
inline void init_NTT(){
	for(int re i=1;i<=bit;++i)w[i]=new int[1<<i-1];
	int wn=power(3,mod-1>>bit);w[bit][0]=1;
	for(int re i=1;i<(1<<bit-1);++i)w[bit][i]=mul(w[bit][i-1],wn);
	for(int re i=bit-1;i;--i)
	for(int re j=0;j<(1<<i-1);++j)w[i][j]=w[i+1][j<<1];
	fac[0]=ifac[0]=fac[1]=inv[0]=inv[1]=1;
	for(int re i=2;i<SIZE;++i)fac[i]=mul(fac[i-1],i),inv[i]=mul(inv[mod%i],mod-mod/i);
	ifac[SIZE-1]=power(fac[SIZE-1],mod-2);
	for(int re i=SIZE-2;i;--i)ifac[i]=mul(ifac[i+1],i+1);
}
inline void NTT(Poly &A,int len,int typ){
	for(int re i=0;i<len;++i)if(i<r[i])std::swap(A[i],A[r[i]]);
	for(int re i=1,d=1;i<len;i<<=1,++d)
	for(int re j=0;j<len;j+=i<<1)
	for(int re k=0;k<i;++k){
		int &t1=A[j+k],&t2=A[j+k+i],t=mul(t2,w[d][k]);
		t2=dec(t1,t),Inc(t1,t);
	}
	if(typ==-1){
		std::reverse(A.begin()+1,A.begin()+len);
		for(int re i=0,inv=power(len,mod-2);i<len;++i)Mul(A[i],inv);
	} 
}
inline void init_rev(int l){
	for(int re i=0;i<l;++i)r[i]=r[i>>1]>>1|((i&1)?l>>1:0);
}

inline Poly operator*(Poly a,Poly b){
	int deg=a.size()+b.size()-1,l=1;
	while(l<=deg)l<<=1;init_rev(l);
	a.resize(l),NTT(a,l,1);
	b.resize(l),NTT(b,l,1);
	for(int re i=0;i<l;++i)Mul(a[i],b[i]);
	NTT(a,l,-1),a.resize(deg);
	return a;
}

inline Poly Inv(cs Poly &a,int lim){
	int n=a.size();Poly c,b(1,power(a[0],mod-2));
	for(int re l=4;(l>>2)<lim;l<<=1){
		init_rev(l);
		c.resize(l>>1);for(int re i=0;i<(l>>1);++i)c[i]=i<n?a[i]:0;
		c.resize(l),NTT(c,l,1);
		b.resize(l),NTT(b,l,1);
		for(int re i=0;i<l;++i)Mul(b[i],dec(2,mul(b[i],c[i])));
		NTT(b,l,-1),b.resize(l>>1);
	}b.resize(lim);
	return b;
}

inline Poly Deriv(Poly a){
	for(int re i=0;i+1<a.size();++i)a[i]=mul(a[i+1],i+1);
	a.pop_back();return a;
}

inline Poly Integ(Poly a){a.push_back(0);
	for(int re i=a.size()-1;i;--i)a[i]=mul(a[i-1],inv[i]);
	a[0]=0;return a;
}

inline Poly Ln(Poly a,int lim){
	a=Integ(Deriv(a)*Inv(a,lim));
	a.resize(lim);
	return a;
}
inline Poly Ln(cs Poly &a){return Ln(a,a.size());}

inline Poly Exp(cs Poly &a,int lim){
	Poly c,b(1,1);int n=a.size();
	for(int re l=2;(l>>1)<lim;l<<=1){
		c=Ln(b,l);
		for(int re i=0;i<l;++i)c[i]=dec(i<n?a[i]:0,c[i]);
		Inc(c[0],1);
		b=b*c;b.resize(l);
	}b.resize(lim);
	return b;
}
inline Poly Exp(cs Poly &a){return Exp(a,a.size());}

inline Poly Ksm(cs Poly &a,int t,int lim){
	int bot=0,l=1;
	while(bot<a.size()&&!a[bot])++bot;
	if((ll)t*bot>lim)return Poly(lim,0);
	while(l<lim)l<<=1;
	Poly b(l,0);
	for(int re i=bot;i<lim;++i)b[i-bot]=a[i];
	int p=power(a[bot],mod-2);
	for(int re i=0;i<l;++i)Mul(b[i],p);b=Ln(b,l);
	for(int re i=0;i<l;++i)Mul(b[i],t);b=Exp(b);b.resize(lim);
	p=power(a[bot],t);
	for(int re i=0;i<lim;++i)Mul(b[i],p);
	Poly ans;ans.resize(lim);
	for(int re i=t*bot;i<lim;++i)ans[i]=b[i-t*bot];
	return ans;
}
inline Poly Ksm(cs Poly &a,int k){return Ksm(a,k,a.size());}

Poly f;

signed main(){
#ifdef zxyoi
	freopen("first_stirling_col.in","r",stdin);
	freopen("first_stirling_col.out","w",stdout);
#endif
	init_NTT();
	int n,k;scanf("%d%d",&n,&k);
	f.resize(n+1);
	for(int re i=1;i<=n;++i)f[i]=inv[i];
	f=Ksm(f,k);
	for(int re i=0;i<=n;++i){
		Mul(f[i],mul(ifac[k],fac[i]));
		cout<<f[i]<<" ";
	}
	return 0;
}

你可能感兴趣的:(多项式,生成函数,_____模板_____,组合数学)