聽說每一年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個無差異的盒子中,要求盒子非空,有幾種方案?