听说每一年noip都会考数论的题?!html
蒟蒻表示智商不够,被数论完虐。。。。。ios
因此我就只能在这里整理整理各类数论的板子了。。。。算法
一.素数app
http://www.cnblogs.com/mycapple/archive/2012/08/07/2626898.htmlide
1.欧拉筛(线性筛)函数
int Euler_sieve() { memset(not_prime,0,sizeof(not_prime)); for(int i=2;i<=n;i++) { if(!not_prime[i]) prime[++tot]=i; for(int j=1;j<=tot;j++) { if(i*prime[j]>N) break; not_prime[i*prime[j]]=1; if(i%prime[j]==0) break; } } }//若 not_prime[i]为0则为素数 注意:not_prime[1]=1;
2.简单的素数断定spa
int pd(int x) { for(int i=2;i*i<=x;i++) if(x%i==0) return false; return true; }
二.欧几里得+扩展欧几里得.net
讲解:http://blog.csdn.net/zhjchengfeng5/article/details/7786595 3d
1.欧几里得code
int gcd(int a,int b) { if(b==0) return a; else return gcd(b,a%b); }
2.扩展欧几里得
①求乘法逆元
再求乘法逆元的时候能够用一个更简便的方法,当这个数与他的模数互质时,它的乘法逆元为这个数的mod-2次方。(用快速幂)
int exgcd(int a,int b,int &x,int &y) { if(b==0) { x=1,y=0; return a; } int r=exgcd(b,a%b,x,y),tmp; tmp=x,x=y,y=tmp-a/b*y; return r; } int main() { a=read(),b=read(); gcd=exgcd(a,b,x,y); if(gcd!=1) printf("不存在"); else {while(x<=0) x+=b/gcd; printf("%d",x);} }
②小扩展:除法取模运算
(a/b)mod p=?
定义 c为b在mod p意义下的逆元
=a*c mod p = (a mod p * c mod p)mod p
③求解同余方程
拓展欧得用于求解形如 ax + by = gcd(a,b) 的不定方程的一组解. 该算法保证求出的 x,y 满⾜足|x| + |y| 最小
ax三c(mod b)——> ax+by=c——>咱们能够知道c=gcd*c/gcd,那么原式又能够变成ax/(c/gcd)+by/(c/gcd)=c/(c/gcd)咱们令x1=x/(c/gcd),y1=y/(c/gcd),——>x=x1*(c/gcd) 那么原式又能够变成ax1+by1=gcd; 最终x=x1*c/gcd
④.两我的的追及相遇问题:设咱们用了x时间,一共相差了y圈,总长度为s,A的起点为s1,速度为v1,B的起点为s2,速度为v2,咱们能够列出这样一个式子:s1+v1*x-(s2+v2*x)=y*s——>(v1-v2)*x-s*y=s2-s1.咱们设a=v1-v2,b=-s,c=s2-s1,那么上式就能够化成ax+by=c咱们接着进行化简——>a/c*x+b/c*y=1,设a1=a/c,b1=b/c,c1=c/c.原式就变成了a1*x+b1*y=1,而后就是裸的扩展欧几里得了
三.欧拉函数
http://blog.csdn.net/sentimental_dog/article/details/52002608
求1~n中有几个数与n互质
int get_phi(int x) { int sum=x; if(x%2==0) { while(x%2==0) x/=2; sum/=2; } for(int i=3;i*i<=x;i+=2) { if(x%i==0) { while(x%i==0) x/=i; sum=sum/i*(i-1); } } if(x>1) sum=sum/x*(x-1); return sum; }
小规律:(须要用欧拉函数的状况)
1.对于方阵的问题,咱们若是要求一我的站在一个位置时事业所能看到的人的个数能够将其转换成欧拉函数。咱们将其所在的位置设为(0,0),那么若是存在一个点(x,y),且有gcd(x,y)=k(k!=1),那么点(x/k,y/k)必定会将(x,y)挡住。而若是k=1,那么点(x,y)就必定会被看到。 这样就会想到这不是欧几里得吗??怎么跟欧拉函数扯上关系了??? 某位大佬跟我说你用欧几里得吧,T死你。咱们把这个题的式子列出来
n n n i
∑ ∑ [gcd(i,j) = 1] + 2 将以上式子拆成两半等于 2(∑ ∑ [gcd(i,j)=1]))+1
i=1 j=1 i i=1 j=1
咱们又能够知道 φ(i) =∑ j=1 [gcd(i,j) = 1] 因此就真的变成了裸地欧拉函数
2.求1~n中与n的最大公约数大于m的数的个数
咱们考虑gcd这样一个性质gcd(x,y)=m则gcd(x/m,y/m)=1;咱们就能够轻易的发如今这个地方的x/m不就是咱们要求的第一个式子中的x吗??这样咱们就只须要统计这样的x/m的个数不就行了吗?!发现这样会T的很惨。这样咱们来找一个不T的方法:一个数的最大公约数是否是必定是她的因子。求每个数的公约数的因子的时候是否是能够直接枚举到根n??对于咱们处理出来的因子是否是有两个来源,一个是自己i,另外一个是n/i??
这样咱们就能够分两种状况来判断,一是i>m,另外一种是n/i大于m,这样咱们再求n/i的欧拉函数与n/n/i即i的欧拉函数就行了。
欧拉函数+处理
for(int i=1;i*i<=n;i++) { if(n%i==0) { if(i>=m&&i*i!=n) ans+=get_phi(n/i); if(n/i>=m) ans+=get_phi(i); } }
四.卡特兰数
http://www.cnblogs.com/z360/p/6561567.html
卡特兰数的应用:
1.给定N个节点,能构成多少种不一样的二叉树? 一个有n个结点的二叉树总共有多少种形态
2.在一个凸多边形中,经过若干条互不相交的对角线,把这个多边形划分红了若干个三角形。任务是键盘上输入凸多边形的边数n,求不一样划分的方案数f(n)。 求一个凸多边形区域划分红三角形区域的方法数
3.矩阵链乘: P=a1×a2×a3×……×an,依据乘法结合律,不改变其顺序,只用括号表示成对的乘积,试问有几种括号化的方案?
4.在一个圆上,有2*K个不一样的结点,咱们以这些点为端点,连K条线段,使得每一个结点都刚好用一次。在知足这些线段将圆分红最少部分的前提下,请计算有多少种连线的方法 在一个圆上2*K个不一样的结点连K条线段,每一个结点用一次将圆分红最少部分的前提下有多少种连线的方法
5.出栈次数 给定1-n问出栈序列的种类数
6.n对括号有多少种匹配方式
7.物理老师和生物老师排队,物理老师前面的生物老师的个数不能超过物理老师,问排队方案数
核心代码:
h[0]=1,h[1]=1; for(int i=2;i<=n;i++) for(int j=1;j<=i;j++) h[i]=h[j-1]*h[i-j]+h[i]; ans=h[n];
高精卡特兰数
#define N 110 int n,len,ans,sum,tmp,a[N][N],b[N]; int catelan() { len=1; a[1][0]=b[1]=1; for(int i=2;i<110;i++) { for(int j=0;j<len;j++) a[i][j]=a[i-1][j]*(4*i-2); sum=0; for(int j=0;j<len;j++) { tmp=sum+a[i][j]; a[i][j]=tmp%10; sum=tmp/10; } while(sum) { a[i][len++]=sum%10; sum/=10; } for(int j=len-1;j>=0;j--) { tmp=sum*10+a[i][j]; a[i][j]=tmp/(i+1); sum=tmp%(i+1); } while(!a[i][len-1]) len--; b[i]=len; } }
卡特兰数递推式:f[i][j]=f[i-1][j]+f[i][j-1]
for(int i=0;i<=30;i++) f[i][0]=1; for(int j=1;j<=30;j++) for(int i=j;i<=30;i++) f[i][j]=f[i-1][j]+f[i][j-1];
扩展卡特兰数(这个我也不是很清楚,不要被我忽悠了。。。)
1.有n个1和m个-1(n>=m),共n+m个数排成一列,知足对全部0<=k<=n+m的前k个数的部分和Sk > 0的排列数。 问题等价一个格点阵列中,从(0,0)走到(n,m)且不通过对角线x==y的方法数(x > y)。s=f[n][m] f[i][j]=f[i-1][j]+f[i][j-1]
2.有n个1和m个-1(n>=m),共n+m个数排成一列,知足对全部0<=k<=n+m的前k个数的部分和Sk >= 0的排列数。(和问题1不一样之处在于此处部分和能够为0,这也是更常见的状况) 问题等价为在一个格点阵列中,从(0,0)点走到(n,m)点且不穿过对角线x==y的方法数(能够走到x==y的点)。 把(n,m)点变换到(n+1,m)点,问题变成了问题1。
五.中国剩余定理(孙子定理)
http://www.cnblogs.com/z360/p/7341176.html
求解形如的方程组,其中 m i 两两互质.经常使用于求 m^n (mod p), 其中 n 须要取模而 p 是个质数.
一直在纠结同余方程无解的状况,后一位大佬跟我说的
一次同余方程组有解的条件 不是全部的一次同余方程组都是有解的。特别是有些乱写的同余方程组,都没有解。 一次同余方程组有解的条件是: 一、 方程组之间的模M (即除数),要两两互质。即两个模M一、M2的最大公约(M一、M2)=G,G=1 如 X≡3 ( Mod 4 ) X≡5 ( Mod 7 ) (4 ,7 ) =1,有最小解 X=19 二、 若是不互质,但公约数G能整除两个余数R之差。即G|(R1-R2) ,则亦有解。 如 X≡13 ( Mod 14 ) X≡3 ( Mod 6 ) 虽然6 与14 不互质,(6 ,14) =2,但因为余数13与3之差为13-3=10,2整除10 ( 2∣10 ), 因此仍然有解。用个人方法,解得最小解 X=27。 三、 若是这两个条件都达不到,则方程组无解。 如 X≡12 ( Mod 14 ) X≡3 ( Mod 6 ) 模 (6 ,14) =2,余数之差 12-3=9 ,2不能整除9,因此该同余方程组无解,没必要浪费工夫去硬算了。
模板:(两两互质)
long long crt() { long long M=1,mi=0,ans=0; for(int i=1;i<=n;i++) M*=m[i]; for(int i=1;i<=n;i++) { long long x=0,y=0; mi=M/m[i]; exgcd(mi,m[i],x,y); ans=(ans+a[i]*x*mi)%M; } if(ans<0) ans+=M; return ans; }
(两两不互质)这个让我讲我也不会,就只能背过了、、、、、
int crt() { int a1=a[1],a2,m2,c,d;m1=m[1]; for(int i=2;i<=n;++i) { int x=0,y=0; a2=a[i],m2=m[i]; c=a2-a1; d=exgcd(m1,m2,x,y); int mod=m2/d; if(c%d) return -1; x=x*c/d; x=(x%mod+mod)%mod; a1+=m1*x; m1*=mod; } if(a1==0) a1+=m1; return a1; }
六。斐波那契数列
模板
x=sqrt(5.0); ans=(pow(((1+x)/2),n)/x-pow(((1-x)/2),n)/x);
高精斐波那契
int fei(int a,int b,int c) { for(int i=1;i<=max(len[b],len[c]);i++) { f[a][i]+=f[b][i]+f[c][i]; if(f[a][i]>9) { f[a][i+1]=f[a][i]/10; f[a][i]=f[a][i]%10; len[a]=max(len[a],i+1); } else len[a]=max(len[a],i); } } int main() { n=read(); f[1][1]=1,f[2][1]=2,len[0]=1,len[1]=1; for(int i=3;i<=n;i++) fei(i,i-1,i-2); for(int i=len[n];i>=1;i--) printf("%d",f[n][i]); return 0; }
gcd(f[n],f[m])=f[gcd(n,m)]
求斐波那契第n项,且n比较大时:http://blog.csdn.net/George__Yu/article/details/77249237?locationNum=7&fps=1
矩阵乘法加速斐波那契
http://www.cnblogs.com/z360/p/7687940.html
struct Node { long long m[3][3]; Node(){memset(m,0,sizeof(m));} }mb,ans; int GCD(int a,int b) { if(b==0) return a; return GCD(b,a%b); } Node operator*(Node a,Node b) { Node c; for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) for(int k=1;k<=2;k++) c.m[i][j]=(c.m[i][j]%mod+a.m[i][k]*b.m[k][j]%mod)%mod; return c; } int main() { n=read();n--; mb.m[1][1]=mb.m[1][2]=mb.m[2][1]=1; ans.m[1][1]=ans.m[2][2]=1; while(n) { if(1&n) ans=ans*mb; mb=mb*mb;n>>=1; } cout<<ans.m[1][1]; return 0; }
七:排列组合
http://jingyan.baidu.com/article/63acb44ac60d4e61fcc17e2e.html
排列:知足m<=n,从n个元素中取出m个元素,问这m个元素的排列方案 组合:从n个元素中取出m个元素造成一个组合,问组合数
直接上公式:
不过据学长说,若是%p的话 要是p为素数 就能够搞一下逆元(欧拉函数 gcd均可以)
(a/b)mod p=a*c mod p = (a mod p * c mod p)mod p(定义 c为b在mod p意义下的逆元)
要是p不是素数 就比较恶心了 反正求逆元就是各类错...
质因数分解 而后把分母都给抹了去
这个地方也能够用卢卡斯定理来解决取模的问题
http://baike.sogou.com/v61779857.htm?fromTitle=Lucas%09%E6%95%B0%E8%AE%BA%E5%AE%9A%E7%90%86
模板位置:http://www.cnblogs.com/vongang/archive/2012/12/02/2798138.html(暂时不打算用,何时乘法逆元被卡了再说吧)
Lucas(n,m,p)=c(n%p,m%p)*Lucas(n/p,m/p,p)
int Mi(int a,int b,int p) { int res=1; while(b) { if(b&1) res=res*a%p; b>>=1;a=a*a%p; }return res; } int C(int n,int m,int p) { if(m>n)return 0; return f[n]*Mi(f[m]*f[n-m],p-2,p)%p; } int Lus(int n,int m,int p) { if(m==0) return 1; return (C(n%p,m%p,p)*Lus(n/p,m/p,p))%p; }
one、路径条数:从一个点(a,b)到另外一个点(x,y)路径的总条数C(x-a+y-b,x-a)
two、给一个集合,一共n个元素,从中选取m个元素,知足选出的元素中没有相邻的元素,一共有c(n-m+1,m)种选法
three、求x1+x2+……+xn=m解的个数。利用插板法能够得出x1+x2+……+xn=m解的个数为C(n+m-1,m);
four、在一个长为n,宽为m的矩形当中,从(1,1)点到(n,m)的走法共有才C(n,n+m)种
插板法:http://baike.sogou.com/v10001101.htm?fromTitle=%E6%8F%92%E6%9D%BF%E6%B3%95
代码很简单就不写了吧、、、、、
常见题型:
1.将n个苹果放入m个盒子中,每一个盒子至少放一个,问有多少种放法 sum=C(n-1,m-1)
2.将n个苹果放入m个盒子中,问有多少种放法 sum=C(n+m-1,m-1) 由于没有说箱子种至少放几个,那么箱子中的苹果数目可能 为0,这样咱们就先在箱子中放入一个苹果,这样咱们就至关于有n+m个苹果,要放入m个箱子中了
3.将n个苹果放入m个盒子中,第一个箱子能够放0个苹果,第二个盒子至少放一个苹果,第三个盒子最少放2个苹果、、、、问有多少 种放法 sum=C(n+1-1-2-3-、、、、-(m-2),m) 咱们能够将第一个箱子当作已经放了一苹果,因此这个时候咱们的苹果总 数要+1,而后咱们第三到第m个箱子种放的苹果个数多于1个,咱们能够认为咱们从咱们的n个苹果种先拿出i个放入第i个箱子中,这 样咱们就能够认为咱们的苹果总数为n+1-1-2-3-、、、、-(m-2)个
八:快速幂
http://www.cnblogs.com/z360/p/6920954.html
int kpow(long long n,long long k,long long mod) { long long int res=1; while(k) { if(k&1) res=(res*n)%mod; n=(n*n)%mod; k=k>>1;//每次都将k/2,为使用的二进制,使改代码更快。 } return res; }
快速乘:使乘法减速,可是防止在快速幂的时候报long long(在数小的时侯就尽可能不要用了)
ll multi(ll a,ll b,ll m) { ll ans=0; while(b) { if(b&1) (ans+=a) %= m; (a=a*2) %= m; b/=2; } return ans; } ll pow_mod(ll a,ll b,ll m) { ll res=1; while(b) { if(b&1) res=multi(res,a,m); //这里要用到快速乘 a=multi(a,a,m); b/=2; } return res; }
九:康拓展开
http://blog.csdn.net/acdreamers/article/details/7982067
康托展开表示的是当前排列在n个不一样元素的全排列中的名次。好比213在这3个数全部排列中排第3。
那么,对于n个数的排列,康托展开为:
其中表示第i个元素在未出现的元素中排列第几。
举个简单易懂的例子:
对于排列4213来讲,4在4213中排第3,注意从0开始,2在213中排第1,1在13中排第0,3在3中排第0,即:
,这样获得4213在全部排列中排第ans=20
康拓展开代码:
//康托展开 LL Work(char str[]) { int len = strlen(str); LL ans = 0; for(int i=0; i<len; i++) { int tmp = 0; for(int j=i+1; j<len; j++) if(str[j] < str[i]) tmp++; ans += tmp * f[len-i-1]; //f[]为阶乘 } return ans; //返回该字符串是全排列中第几大,从1开始 }
康托展开的逆运算:
void Work(LL n,LL m) { n--; vector<int> v; vector<int> a; for(int i=1;i<=m;i++) v.push_back(i); for(int i=m;i>=1;i--) { LL r = n % f[i-1]; LL t = n / f[i-1]; n = r; sort(v.begin(),v.end()); a.push_back(v[t]); v.erase(v.begin()+t); } vector<int>::iterator it; for(it = a.begin();it != a.end();it++) cout<<*it; cout<<endl; }
求一个排列在全排列中的名次以及已知一个排列的名次,求该全排列
#include<vector> #include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define N 21000 #define ll long long using namespace std; char ch; bool vis[N]; ll x,s[N],ans,ans1[N],n,m,t,sum,v[N],str[N]; ll read() { ll x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f; } ll work1(ll x)//康拓展开的逆运算 { memset(ans1,0,sizeof(ans1)); for(int i=1;i<=n;i++) v[i]=i; for(int i=n;i>=1;i--) { t=x/s[i-1]; x%=s[i-1]; t++; sort(v+1,v+1+n); ans1[n-i+1]=v[t]; v[t]=N; } for(int i=1;i<=n;i++) printf("%lld ",ans1[i]); } int work2()//康拓展开 { for(int i=1;i<=n;i++) { sum=0; for(int j=i+1;j<=n;j++) if(str[j]<str[i]) sum++;//sum统计比当前数小的个数 ans+=s[n-i]*sum;//康拓展开公式,n-i=(n-i+1)-1; } return ans++;//为何++,由于咱们求出的是有都少排列比这个排列小,那么到当前排列就要加1 } int main() { n=read(),m=read();s[0]=1; for(int i=1;i<=n;i++) s[i]=s[i-1]*i;//预处理阶乘 while(m--) { cin>>ch; if(ch=='P') { x=read(); x--;//为何要减一??由于咱们康拓展开是求的有多少数比当前的小,也就是说咱们求出的是比当前排列要大一的排列,因此这个地方咱们要减一 work1(x); printf("\n"); } else { ans=0; for(int i=1;i<=n;i++) str[i]=read(); work2(); printf("%lld\n",ans); } } }
十:错排
https://baike.baidu.com/item/%E9%94%99%E6%8E%92%E5%85%AC%E5%BC%8F
错排:考虑一个有n个元素的排列,若一个排列中全部的元素都不在本身原来的位置上,那么这样的排列就称为原排列的一个错排。
错排递推式:D(n)=(D(n-1)+D(n-2))*(n-1)
错排通项公式:D(n) = n! [(-1)^2/2! + … + (-1)^(n-1)/(n-1)! + (-1)^n/n!]
递推写法 f[2]=1; for(int i=3;i<=n;i++) f[i]=(f[i-1]+f[i-2])*(i-1);
高精
int cp() { f[1][1]=0;f[2][1]=b[2]=b[1]=1; for(int i=3;i<=n;i++) { b[i]=max(b[i-1],b[i-2]); for(int j=1;j<=b[i];j++) { f[i][j]+=f[i-1][j]+f[i-2][j]; f[i][j+1]+=f[i][j]/10; f[i][j]%=10; } while(f[i][b[i]+1]) { b[i]++; f[i][b[i]+1]+=f[i][b[i]]/10; f[i][b[i]]%=10; } for(int tmp=0,j=1;j<=b[i];j++) { f[i][j]=f[i][j]*(i-1)+tmp; if(f[i][j]>9) { tmp=f[i][j]/10; f[i][j]%=10; b[i]=max(b[i],j+1); } else tmp=0; } while(f[i][b[i]+1]) { b[i]++; f[i][b[i]+1]+=f[i][b[i]]/10; f[i][b[i]]%=10; } } }
高精压位 http://www.cnblogs.com/hoskey/p/3722416.html
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define N 15100 #define mod 100000000 using namespace std; int n,s; long long f[5001][N],l[5001]; int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f; } int cp() { f[1][1]=0,f[2][1]=l[1]=l[2]=1; for(int i=1;i<=n;i++) { l[i]=l[i-1]; for(int j=1;j<=l[i];j++) f[i][j]=f[i-1][j]+f[i-2][j]; for(int j=1;j<=l[i];j++) { f[i][j+1]+=f[i][j]/mod; f[i][j]%=mod; } while(f[i][l[i]+1]) l[i]++; for(int j=1;j<=l[i];j++) f[i][j]*=(i-1); for(int j=1;j<=l[i];j++) { f[i][j+1]+=f[i][j]/mod; f[i][j]%=mod; } while(f[i][l[i]+1]) l[i]++; } } int main() { n=read(); cp(); printf("%lld",f[n][l[n]]); for(int i=l[n]-1;i>=1;i--) printf("%08lld",f[n][i]); return 0; }
十一:逆序对
http://www.cnblogs.com/z360/p/6921604.html
咱们能够用逆序对的个数求将一列数排成有序的一列数交换的次数
void gsort(int l,int r) { if(l==r) return ; int mid=(l+r)/2; gsort(l,mid);gsort(mid+1,r); int i=l,j=mid+1,k=l; while(i<=mid&&j<=r) { if(a[i]<=a[j]) tmp[k++]=a[i++]; else { ans+=(long long)(mid-i+1); tmp[k++]=a[j++]; } } while(i<=mid) tmp[k++]=a[i++]; while(j<=r) tmp[k++]=a[j++]; for(int i=l;i<=r;i++) a[i]=tmp[i]; }
十二:容斥原理
http://www.cnblogs.com/z360/p/6361230.html
立方差公式:
(a+b)(a²-ab+b²)=a³+b³
(a-b)(a²+ab+b²)=a³-b³
(a-b)^3=(a-b)(a-b)(a-b)=(a^2-2ab+b^2)(a-b)=a^3-3a^2b+3ab^2-b^3
(a+b)^3=a^3+3a^2b-3ab^2+b^3
等差数列公式:
求第n项:①an=a1+(n-1)*d,d为公差 ②an=am+(n-m)*d
求前n项和:①S=n*(s1+sn)/2 ②S=a1*n+n*(n-1)/2*d
等比数列公式:① S=a1*(1-q^n)/(1-q) (q!=1) ②S=a1*n (q=1)
优先队列:
priority_queue<int>que; 大根堆,堆顶是最大的
priority_queue<int ,vector<int>, greator<int> >que 小根堆
杨辉三角的性质
void Prepare() { for(int i=1; i<=n; ++i) { C[i][0]=C[i][i]=1; for(int j=1; j<i; ++j) C[i][j]=(C[i-1][j-1]%p+C[i-1][j]%p)%p; } }
十5、斯特林数(Stirling数)
https://baike.baidu.com/item/%E6%96%AF%E7%89%B9%E6%9E%97%E6%95%B0/4938529?fr=aladdin
striling数分为两类,分别称为第一类stirling数跟第二类stirling数
第一类striling数
表示将 n 个不一样元素构成m个圆排列的数目
第二类striling数
表示将n个不一样的元素拆分红m个集合的方案数,和第一类Stirling数不一样的是,集合内是不考虑次序的,而圆排列是有序的。经常用于解决组合数学中几类放球模型。描述为:将n个不一样的球放入m个无差异的盒子中,要求盒子非空,有几种方案?