斯特林数分为第一类斯特林数和第二类斯特林数,第一类斯特林数分为有符号斯特林数和无符号斯特林数;
1.什么是圆排列?
圆排列是把n个数中拿出k个数组成一个圆的种类数,则这里组成m个圆排列的意思是组成m个不同的圆的种类数;
2.第一类斯特林数:
斯特林数:
第一类斯特林数表示的是将n个不同元素分成k个不同的环的方案数。两个环不相同当且仅当这两个环不能通过旋转得到。
2.1有符号斯特林数公式:
考虑递推,把n个不同元素分成k个不同的环有两种转移。第一种,有可能是n−1个不同元素分成k−1个不同的环,当前的第n个独立成一个元素。第二种可能是n−1个不同元素已经分好了k个不同的环,当前这个可以加进去。加在每个已有元素的逆时针方向(或顺时针方向,方向没有关系,只要统一即可)就不会出现重复,共有n−1种方法。
第一类斯特林数的递推式:
s(n,k)=s(n−1,k−1)+s(n−1,k)∗(n−1);
2.2有符号斯特林数性质
1.s(0,0)=1s(0,0)=1
2.s(n,0)=0 n>0s(n,0)=0 n>0
3.s(n,1)=(n−1)!s(n,1)=(n−1)!
4.s(n,n−1)=C2ns(n,n−1)=Cn2
5.s(n,2)=(n−1)!∗∑n−1i=11is(n,2)=(n−1)!∗∑i=1n−11i
6.s(n,n−2)=2C3n+3C4ns(n,n−2)=2Cn3+3Cn4
7.∑nk=0s(n,k)=n!
8.s(n,n)=1;
2.3有符号和无符号的关系:
3.第二类斯特林数:
第二类斯特林数表示把n个元素分成k个非空集合的方案数,集合内是无序的。这样,我们很容易得出转移:分为两种情况。第一种情况,如果前n−1个元素组成了k−1个非空集合,那么当前元素自成一个集合。第二种情况,如果前n−1个元素组成了k个集合,那么当前的这个元素可以放进这k个集合中任意的一个。所以递推方程:
S(n,k)=S(n−1,k−1)+S(n−1,k)∗k
3.1 性质
1.S(0,0)=1S(0,0)=1
2.S(n,0)=0,n>0S(n,0)=0,n>0
3.S(n,n)=1S(n,n)=1
4.S(n,2)=S(n−1,1)+S(n−1,2)∗2=1+S(n−1,2)∗2=2n−1+1S(n,2)=S(n−1,1)+S(n−1,2)∗2=1+S(n−1,2)∗2=2n−1+1
5.S(n,n−1)=C2nS(n,n−1)=Cn2
6.S(n,n−2)=C3n+3C4nS(n,n−2)=Cn3+3Cn4 简单巧妙的证明:我们分成两种情况,把nn个不同的元素分成n−2n−2个集合有两种情况,分别是有一个集合有三个元素和有两个集合有两个元素。对于前者,我们选出三个元素为一个集合,其他的各成一个集合,这种情况的方案数就是C3nCn3。对于后者,先选出四个元素来,考虑怎么分配。当其中一个元素选定另一个元素形成同一个集合时,这种情况就确定了,所以是3C4n3Cn4。加法原理计算和即得证。
7.S(n,3)=12(3n−1+1)−2n−1S(n,3)=12(3n−1+1)−2n−1 数学归纳法
8.S(n,n−3)=C4n+10C5n+15C6nS(n,n−3)=Cn4+10Cn5+15Cn6 同性质六
9.通项公式:S(n,m)=1m!∑k=0m(−1)kCkm(m−k)n
参考:https://www.cnblogs.com/owenyu/p/6724661.html
未学会知识:利用斯特林公式求组合数;
4.斯特林公式
斯特林公式(Stirling’s approximation)是一条用来取n的阶乘的近似值的数学公式;
应用:求n!的位数
两种方法:
ans= lg(n!) = lg 1 + lg2 + ……+ lg n.
代码:
#include
#include
double reback(int n)
{
double cnt=0;
for(int i=2;i<=n;i++)
{
cnt+=log10(i);
}
return cnt;
}
int main()
{
int cas,n;
scanf("%d",&cas);
while(cas--)
{
scanf("%d",&n);
printf("%d\n",(int)reback(n)+1);
}
return 0;
}
#include
#include
const double PI = acos(-1.0);
const double ln_10 = log(10.0);
double reback(int N)
{
return ceil((N*log(double(N))-N+0.5*log(2.0*N*PI))/ln_10);
}
int main()
{
int cas,n;
scanf("%d",&cas);
while(cas--)
{
scanf("%d",&n);
if(n<=1)printf("1\n");
else printf("%.0lf\n",reback(n));
}
return 0;
}