排列组合
前言
说实话这是我小学时的噩梦
正文
为了更好的理解基础概念,我们用一个题来展开:
给定一个集合\(S\),内有\(n\)个元素,且\(1-n\)每个数恰好出现一次
如果不计顺序,求出从集合\(S\)中选出\(m\;(m<=n)\)个元素的方案数
- 不计顺序就是说\((1,3,2)\) 和 \((1,2,3)\)算两种方案
我们想:既然不计顺序,则第一个数有\(n\)种选择方案,对于每种方案,第二个数有\(n-1\)种选择方案,第三个数有\(n-2\)种
以此类推,第\(m\)个数有\(n-m\)种选择方案
所以:\(A^m_n=n\times(n-1)\times(n-2)\times\dots\times(n-m)=\dfrac{n!}{(n-m)!}\)
如果计顺序呢?
也就是说\((1,3,2)\) 和 \((1,2,3)\)算一种方案
设\(\lambda(x)\)为含有\(x\)个的元素的集合的全排列个数
则我们发现,每个重复的集合都被恰好计算了\(\lambda(m)\)次
所以:\(C^m_n=\dfrac{A^m_n}{\lambda(m)}=\dfrac{A^m_n}{m!}=\dfrac{n!}{m!(n-m)!}\)
插空与隔板
例如这么两个题
[1]已知三元一次方程\(x+y+z=13\),求这个方程的正整数解的个数
高斯消元党请自觉往下面去
乍一看 这是什么玩意 这完全没有思路
但意思其实就是给你13个球,让你用两块板子将其分隔成三部分
既然分隔,所以我们看的不是球的个数,而是空隙的个数
所以答案为:\(C^2_{12}=66\)
验证程序:
#include<iostream>
#define F(a,b) for(int a=1;a<=b;a++)
int ans;
signed main(){
F(i,13) F(o,13) F(p,13)
if(i+o+p==13) ans+=1;
std::cout<<ans;
}
out: 66
[2]已知三元一次方程\(x+y+z=13\),求这个方程的非负整数解的个数
非负说明了可能有零的出现
意思其实就是给你13个球,让你分到3个箱子里,每个箱子允许不放
就等价于每个箱子事先放进去1个,然后13个球让你分到3个箱子里,每个箱子里至少有一个
就相当于16个球用俩板子分成三部分
所以答案为:\(C^2_{15}=105\)
验证程序:
#include<iostream>
#define F(a,b) for(int a=0;a<=b;a++)
int ans;
signed main(){
F(i,13) F(o,13) F(p,13)
if(i+o+p==13) ans+=1;
std::cout<<ans;
}
out: 105