码迷,mamicode.com
首页 > 其他好文 > 详细

[]斯特林数

时间:2018-04-03 22:16:39      阅读:206      评论:0      收藏:0      [点我收藏+]

标签:一个   方案   表示   style   --   AC   scan   mat   bin   

第二类斯特林数$\left\{\begin{matrix}n\\m\end{matrix}\right\}$表示把含有$n$个不同的数的集合划分为$m$个非空子集的方案数

递推式$\left\{\begin{matrix}n\\m\end{matrix}\right\}=m\left\{\begin{matrix}n-1\\m\end{matrix}\right\}+\left\{\begin{matrix}n-1\\m-1\end{matrix}\right\}$,边界$\left\{\begin{matrix}n\\0\end{matrix}\right\}=[n=0]$,可以这样看:已经分好了$n-1$个数,第$n$个数可以单独分成一个子集,也可以分到之前的$m$个子集中(因为这些子集中有数,所以它们是不同的)

一个固定$n$的通项公式$\begin{align*}\left\{\begin{matrix}n\\m\end{matrix}\right\}=\dfrac1{m!}\sum\limits_{k=0}^m(-1)^k\binom mk(m-k)^n\end{align*}$,相当于从不管非空子集限制的方案($m^n$)中容斥掉有$k$个空子集的方案

它具有卷积的形式,可以用FFT在$O(m\log_2m)$的时间内算出$\left\{\begin{matrix}n\\1\end{matrix}\right\}\cdots\left\{\begin{matrix}n\\m\end{matrix}\right\}$

第一类斯特林数$\left[\begin{matrix}n\\m\end{matrix}\right]$表示把$n$个不同的数划分为$m$个非空轮换的方案数

递推式$\left[\begin{matrix}n\\m\end{matrix}\right]=(n-1)\left[\begin{matrix}n-1\\m\end{matrix}\right]+\left[\begin{matrix}n-1\\m-1\end{matrix}\right]$,边界$\left[\begin{matrix}n\\0\end{matrix}\right]=[n=0]$,可以这样看:已经分好了$n-1$个数,第$n$个数可以单独分成一个轮换,也可以分到之前的轮换中,我们把它插到每个轮换的每一个数后面都可以形成新的轮换,所以有$n-1$种方法

它的另一个定义是$\begin{align*}x^\underline n=\sum\limits_{k=0}^n(-1)^{n-k}\left[\begin{matrix}n\\k\end{matrix}\right]x^k\end{align*}$,用归纳法易证它满足上面的递推性质

$\begin{align*}x^\underline n&=(x-n+1)x^\underline{n-1}\\&=(x-n+1)\sum\limits_{k=0}^{n-1}(-1)^{n-1-k}\left[\begin{matrix}n-1\\k\end{matrix}\right]x^k\\&=\left(\sum\limits_{k=1}^n(-1)^{n-k}\left[\begin{matrix}n-1\\k-1\end{matrix}\right]x^k\right)+\left(\sum\limits_{k=0}^{n-1}(-1)^{n-k}(n-1)\left[\begin{matrix}n-1\\k\end{matrix}\right]x^k\right)\\&=\sum\limits_{k=0}^n(-1)^{n-k}\left((n-1)\left[\begin{matrix}n-1\\k\end{matrix}\right]+\left[\begin{matrix}n-1\\k-1\end{matrix}\right]\right)x^k\end{align*}$

好像没有通项,但是要求还是可以的,考虑计算$x^\underline n$的各项系数,我们采用分治的做法:由$x^\underline n$推$x^\underline{2n}$

如果已经计算好了$\begin{align*}x^\underline n=\sum\limits_{i=0}^n(-1)^{n-i}\left[\begin{matrix}n\\i\end{matrix}\right]x^i\end{align*}$,因为$x^\underline{2n}=x^\underline n(x-n)^\underline n$,所以我们还要计算$(x-n)^\underline n$

$\begin{align*}(x-n)^\underline n&=\sum\limits_{i=0}^n(-1)^{n-i}\left[\begin{matrix}n\\i\end{matrix}\right](x-n)^i\\&=\sum\limits_{i=0}^n(-1)^{n-i}\left[\begin{matrix}n\\i\end{matrix}\right]\sum\limits_{j=0}^i\binom ijx^j(-n)^{i-j}\end{align*}$

第二个sigma是卷积的形式,我们可以用FFT预处理,最后再用FFT把两个多项式乘起来,设时间复杂度为$T(n)$,则$T(n)=O(n\log_2n)+T\left(\dfrac n2\right)$,解得$T(n)=O(n\log_2n)$,也就是说我们可以在$O(n\log_2n)$的时间内算出$\left[\begin{matrix}n\\1\end{matrix}\right]\cdots\left[\begin{matrix}n\\n\end{matrix}\right]$

上面就是这两个东西本身的性质,应用嘛...并没有想到什么

算了先挂一个BZOJ4555充数吧==

题意:求$\begin{align*}\sum\limits_{i=0}^n\sum\limits_{j=0}^i\left\{\begin{matrix}i\\j\end{matrix}\right\}2^jj!\end{align*}$

$\begin{align*}\sum\limits_{i=0}^n\sum\limits_{j=0}^n\left\{\begin{matrix}i\\j\end{matrix}\right\}2^jj!&=\sum\limits_{i=0}^n\sum\limits_{j=0}^n2^j\sum\limits_{k=0}^j(-1)^{j-k}\binom jkk^i\\&=\sum\limits_{j=0}^n2^jj!\sum\limits_{k=0}^j\dfrac{(-1)^{j-k}}{(j-k)!}\dfrac1{k!}\sum\limits_{i=0}^nk^i\end{align*}$

第三个sigma是等比数列求和(注意当$k=0$时求和结果是$1$),第二个sigma有卷积的形式,可以用FFT预处理

庆祝一下==我终于真正会写FFT/NTT了...(菜,没办法)

#include<stdio.h>
const int mod=998244353;
typedef long long ll;
int mul(int a,int b){return a*(ll)b%mod;}
int ad(int a,int b){return(a+b)%mod;}
int de(int a,int b){return(a-b)%mod;}
int pow(int a,int b){
	int s=1;
	while(b){
		if(b&1)s=mul(s,a);
		a=mul(a,a);
		b>>=1;
	}
	return s;
}
int rev[300010],N,iN;
void pre(int n){
	int k,i;
	for(N=1,k=0;N<=n;N<<=1)k++;
	for(i=0;i<N;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
	iN=pow(N,mod-2);
}
void swap(int&a,int&b){a^=b^=a^=b;}
void ntt(int*a,int on){
	int i,j,k,t,w,wn;
	for(i=0;i<N;i++){
		if(i<rev[i])swap(a[i],a[rev[i]]);
	}
	for(i=2;i<=N;i<<=1){
		wn=pow(3,(on==1)?(mod-1)/i:(mod-1-(mod-1)/i));
		for(j=0;j<N;j+=i){
			w=1;
			for(k=0;k<i>>1;k++){
				t=mul(a[i/2+j+k],w);
				a[i/2+j+k]=de(a[j+k],t);
				a[j+k]=ad(a[j+k],t);
				w=mul(w,wn);
			}
		}
	}
	if(on==-1){
		for(i=0;i<N;i++)a[i]=mul(a[i],iN);
	}
}
int a[300010],b[300010],fac[300010],rfac[300010],inv[300010];
int main(){
	int n,i,s,bas;
	scanf("%d",&n);
	fac[0]=1;
	for(i=1;i<=n;i++)fac[i]=mul(fac[i-1],i);
	rfac[n]=pow(fac[n],mod-2);
	for(i=n;i>0;i--)rfac[i-1]=mul(rfac[i],i);
	for(i=1;i<=n;i++)inv[i]=mul(rfac[i],fac[i-1]);
	for(i=0;i<=n;i++){
		a[i]=((i&1)?-1:1)*rfac[i];
		if(i==0)
			b[i]=1;
		else if(i==1)
			b[i]=mul(n+1,rfac[i]);
		else if(i>1)
			b[i]=mul(mul(pow(i,n+1)-1,inv[i-1]),rfac[i]);
	}
	pre(n<<1);
	ntt(a,1);
	ntt(b,1);
	for(i=0;i<N;i++)a[i]=mul(a[i],b[i]);
	ntt(a,-1);
	s=0;
	bas=1;
	for(i=0;i<=n;i++){
		s=ad(s,mul(mul(bas,fac[i]),a[i]));
		bas=mul(bas,2);
	}
	printf("%d",(s+mod)%mod);
}

第一类斯特林数我只遇到过一个:[xsy1515]小学生数学题,如果一道题中的自然数幂求和$n$很大,要求多个,甚至模数不同,那么就可以转成斯特林数$O(k^2)$做

很空虚==毕竟做题太少没什么题放出来

[]斯特林数

标签:一个   方案   表示   style   --   AC   scan   mat   bin   

原文地址:https://www.cnblogs.com/jefflyy/p/8711033.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!