@[TOC]
排列组合
定义
排列()定义:**从个不同元素中取出个元素,按照一定的顺序排成一列,叫做从个元素中取出个元素的一个排列**。
从个不同元素中取出个不同元素,所有不同排列的个数称为排列种数或称排列数,记为(排列数旧版记作,都一样)。
组合()定义:**从个不同的元素中,任取个元素为一组,叫作从个不同元素中取出个元素的一个组合。**
从个元素中不重复地选取个元素的一个组合。所有这样的组合的总数称为组合数,记作或。
组合公式
1.证明
2.证明
3.证明
这里我们需要使用二项式展开式。
我们知道:
我们令
则,得证。
4.证明
我们令:
由上一个定理知:
因为左右相等,所以我们要对应才行啊。
又因为有项。
所以:
两边约掉后得证。
盒子放求问题
1.球相同,盒不同,无空盒
我们使用隔板法。
这种问题就相当于是:在个球缝隙之间插入个隔板,将球分成份。
所以。
代码
#include <bits/stdc++.h> using namespace std; int n,m; int Factorial(int x) { int ans=1; for(int i=2;i<=x;i++) ans*=i; return ans; } int Combination(int n,int m) { return Factorial(n)/Factorial(m)/Factorial(n-m); } int main() { scanf("%d %d",&n,&m); printf("%d",Combination(n-1,m-1)); return 0; }
2.球相同,盒不同,可以空盒
我们就预先在个盒中加一个虚拟球,然后问题就转换成了第一个问题。 。
代码
#include <bits/stdc++.h> using namespace std; int n,m; int Factorial(int x) { int ans=1; for(int i=2;i<=x;i++) ans*=i; return ans; } int Combination(int n,int m) { return Factorial(n)/Factorial(m)/Factorial(n-m); } int main() { scanf("%d %d",&n,&m); printf("%d",Combination(n+m-1,m-1)); return 0; }
3.球不同,盒相同,无空盒
这就是第二类斯特林数:
我们定义为前个球放入个盒子的方案数。
我们把这个球放在前个盒子中,就有种方案。
我们把这个球放在第个新盒子中,就有种方案。
所以状态转移方程式为:
f[i][j]=j*f[i-1][j]+f[i-1][j-1];
我们的初始化为:
f[0][0]=1;
代码
#include <bits/stdc++.h> using namespace std; int n,m,f[15][15]; int main() { scanf("%d %d",&n,&m); f[0][0]=1; for(int i=1;i<=n;i++) { for(int j=0;j<=m;j++) f[i][j]=j*f[i-1][j]+f[i-1][j-1]; } printf("%d",f[n][m]); return 0; }
4.球不同,盒相同,可以空盒
这道题与第三道很像。
状态转移方程式:
for(int i=1;i<=m;i++) ans+=f[n][i];
我们就分别把个球放进前个盒子,把个球放进前个盒子...把个球放进前个盒子。
代码
#include <bits/stdc++.h> using namespace std; int n,m,f[15][15],ans; int main() { scanf("%d %d",&n,&m); f[0][0]=1; for(int i=1;i<=n;i++) { for(int j=0;j<=m;j++) f[i][j]=j*f[i-1][j]+f[i-1][j-1]; } for(int i=1;i<=m;i++) ans+=f[n][i]; printf("%d",ans); return 0; }
5.球不同,盒不同,无空盒
我们可以看做第三个问题。只是因为盒子不同,所以我们需要将盒子排个序,共有:
所以
代码
#include <bits/stdc++.h> using namespace std; int n,m,f[15][15],ans=1; int main() { scanf("%d %d",&n,&m); f[0][0]=1; for(int i=1;i<=n;i++) { for(int j=0;j<=m;j++) f[i][j]=j*f[i-1][j]+f[i-1][j-1]; } for(int i=2;i<=m;i++) ans*=i; printf("%d",ans*f[n][m]); return 0; }
6.球不同,盒不同,可以空盒
每个球都可以选任意盒子,每个球有种选法,所以个球就有: 。
代码
#include <bits/stdc++.h> using namespace std; int n,m; int Quick_Power(int a,int b) { int ans=1; while(b) { if(b&1) ans=ans*a; b>>=1,a=a*a; } return ans; } int main() { scanf("%d %d",&n,&m); printf("%d",Quick_Power(m,n)); return 0; }
7.球相同,盒相同,无空盒
我们定义为个球个盒子的方案数。
则:
for(int k=1;k<=j;k++) f[i][j]=(f[i][j]+f[i-j][k])%MOD;
我们先铺个球分别到个盒子,然后剩下个球随便放。
代码
#include <bits/stdc++.h> using namespace std; const int MOD=12345; int n,m,f[1005][1005]; int main() { scanf("%d %d",&n,&m); for(int i=1;i<=n;i++) f[i][1]=f[i][i]=f[i][i-1]=1; for(int i=1;i<=n;i++) { for(int j=2;j<=min(m,i-2);j++) { for(int k=1;k<=j;k++) f[i][j]=(f[i][j]+f[i-j][k])%MOD; } } printf("%d",f[n][m]); return 0; }
8.球相同,盒相同,可以空盒
我们就放个虚拟球分别到个盒子,然后个球随便放。
代码
#include <bits/stdc++.h> using namespace std; const int MOD=12345; int n,m,f[2005][1005]; int main() { scanf("%d %d",&n,&m); n+=m; for(int i=1;i<=n;i++) f[i][1]=f[i][i]=f[i][i-1]=1; for(int i=1;i<=n;i++) { for(int j=2;j<=min(m,i-2);j++) { for(int k=1;k<=j;k++) f[i][j]=(f[i][j]+f[i-j][k])%MOD; } } printf("%d",f[n][m]); return 0; }