【数学】之组合计数基础入门与简单例题

组合计数

加法原理

e.g.e.g.e.g.若完成一件事的方法有 nnn 类,其中第 iii 类方法包括 aia_iai 种不同的方法,且这些方法互不重合,则完成这件事共有 a1+a2+...+ana_1+a_2+...+a_na1+a2+...+an种不同的方法。

乘法原理

e.g.e.g.e.g. 若完成一件事需要 nnn 个步骤,其中第 iii 个步骤有 aia_iai 种不同的完成方法,且这些步骤互不干扰,则完成这件事共有 a1×a2×a3×...×ana_1 \times a_2 \times a_3 \times ... \times a_na1×a2×a3×...×an 种不同的方法。

例题:洛谷P3197 [HNOI2008] 越狱 https://www.luogu.com.cn/problem/P3197

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define Mod 100003
int n , m , ans ;
int ksm(int x , int y ,int p)
{
	int res = 1 ;
	for( ; y ; y >>= 1)
	{
		if(y & 1)
			res = (res * x) % p ;
		x = (x * x) % p ;
	}
	return res ;
}
signed main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin >> m >> n ;
	ans = ksm(m , n , Mod) - (ksm(m - 1 , n - 1 , Mod) * m) % Mod ;
	ans = (ans + Mod) % Mod ;
	cout << ans ; 
	return 0;
}

正难则反

排列数

e.g.e.g.e.g.nnn 个不同元素中 依次 取出 mmm 个元素排成一列,产生的不同排列的数量为:
Anm=n!(n−m)!=n×(n−1)×⋯×(n−m+1) \boxed{ A_n^m = \frac{n!}{(n-m)!} = n \times (n-1) \times \cdots \times (n-m+1) } Anm=(nm)!n!=n×(n1)××(nm+1)
也可以写作:Anm (或 Pnm)=n!(n−m)!=∏k=0m−1(n−k)\boxed{A_n^m \ (\text{或} \ P_n^m) = \frac{n!}{(n-m)!} = \prod_{k=0}^{m-1} (n-k)}Anm ( Pnm)=(nm)!n!=k=0m1(nk)

其中:

  • ( n ) 表示总元素个数
  • ( m ) 表示选取元素个数
  • ( n! ) 表示 ( n ) 的阶乘

组合数

e.g.e.g.e.g.nnn 个不同元素中取出 mmm 个组成一个集合**(不考虑顺序)**,产生的不同集合数量为:

Cnm=n!m!(n−m)!=n×(n−1)×⋯×(n−m+1)m×(m−1)×⋯×2×1\boxed{C_n^m = \frac{n!}{m!(n-m)!} = \frac{n \times (n-1) \times \cdots \times (n-m+1)}{m \times (m-1) \times \cdots \times 2 \times 1}}Cnm=m!(nm)!n!=m×(m1)××2×1n×(n1)××(nm+1)

性质
  1. Cnm=Cnn−mC_n^m = C_n^{n-m}Cnm=Cnnm
  2. $ C_n^m = C_{n-1}^m + C_{n-1}^{m-1}$
  3. $ C_n^0 + C_n^1 + C_n^2 + \cdots + C_n^n = 2^n$
类比杨辉三角

例题:洛谷P5732 【深基5.习7】杨辉三角 https://www.luogu.com.cn/problem/P5732

#include<bits/stdc++.h>
using namespace std;
int n , c[50][50] ;
int main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin >> n ;
	c[0][0] = 1 ;
	for(int i = 1 ; i <= n ; i ++)
	{
		c[i][0] = 1 ;
		for(int j = 1 ; j <= i ; j ++)
			c[i][j] = c[i - 1][j - 1] + c[i - 1][j] ;
	}
	for(int i = 0 ; i < n ; i ++)
		for(int j = 0 ; j <= i ; j ++)
			cout << c[i][j] << " \n"[j == i] ;
	return 0;
}

隔板法

又叫插板法

例题:洛谷P5520 [yLOI2019] 青原樱 https://www.luogu.com.cn/problem/P5520

#include<bits/stdc++.h>
using namespace std;
long long t , n , m , p , ans = 1 ;
int main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin >> t >> n >> m >> p ;
	for(int i = n - m + 1 ; i >= n - (m << 1) + 2 ; i --)
		ans = (ans * i) % p ;
	cout << ans ;
	return 0;
}

直接填难度太大,考虑转化,mmm 个填数位置以外恰好有 n−mn - mnm 个位置不用填,n−mn - mnm 个位置中间有 n−m−1n - m - 1nm1 个位置可以插入,除此之外 n−mn - mnm 的两端也可以插入,共计 n−m+1n - m + 1nm+1 个位置可以插入数字,此时答案就是 n−m+1n - m + 1nm+1 个空隙里头有顺序的选择 mmm 个(因为 mmm 个数之间有区别),所以答案是 P(n−m+1,m)=(n−m+1)!(n−2×m+1)!P(n-m+1,m)=\frac{(n-m+1)!}{(n-2 \times m+1)!}P(nm+1,m)=(n2×m+1)!(nm+1)!for循环n−2×m+2n - 2 \times m + 2n2×m+2 一直乘到 n−m+1n - m + 1nm+1 就行了

类比 Anm=n×(n−1)×(n−2)×...×(n−m+1)A_n^m = n \times (n - 1) \times (n-2) \times ... \times (n-m+1)Anm=n×(n1)×(n2)×...×(nm+1)

拓展到 An+1m=(n+1)×n×(n−1)×(n−2)×...×(n−m)A_{n+1}^m = (n+1) \times n \times (n-1) \times (n-2) \times ... \times (n-m)An+1m=(n+1)×n×(n1)×(n2)×...×(nm)

得到本题 An+1−mm=(n+1−m)×(n−m)×(n−m−1)×(n−m−2)×...(n+2−2×m)A_{n+1-m}^m = (n+1-m) \times (n-m) \times (n-m-1) \times (n-m-2) \times ...(n+2-2 \times m)An+1mm=(n+1m)×(nm)×(nm1)×(nm2)×...(n+22×m)

二项式定理

(a+b)n=∑k=0nCnkakbn−k(a+b)^n=\sum_{k=0}^n C_n^k a^k b^{n-k}(a+b)n=k=0nCnkakbnk

类比和的平方公式,和的立方公式。

例题:洛谷P1313 [NOIP 2011 提高组] 计算系数 https://www.luogu.com.cn/problem/P1313

#include<bits/stdc++.h>
using namespace std;
#define Mod 10007
#define int long long
int a , b , k , n , m , ans , c[1010][1010] ;
int ksm(int x , int y , int p)
{
	int res = 1 ;
	for( ; y ; y >>= 1)
	{
		if(y & 1) res = (res * x) % p ;
		x = (x * x) % p;
	}
	return res ;
}
signed main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin >> a >> b >> k >> n >> m ;
	c[0][0] = 1 ;
	for(int i = 1 ; i <= k ; i ++)
	{
		c[i][0] = 1 ;
		for(int j = 1 ; j <= i ; j ++)
		{
			c[i][j] = c[i - 1][j - 1] + c[i - 1][j] ;
			c[i][j] %= Mod ;
		}
	}
	ans = (c[k][n] * ksm(a , n , Mod) * ksm(b , m ,Mod)) % Mod ;
	cout << ans ;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值