@[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;
} 总结


京公网安备 11010502036488号