专栏文章

by组合计数

个人记录参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mipknd8p
此快照首次捕获于
2025/12/03 13:33
3 个月前
此快照最后确认于
2025/12/03 13:33
3 个月前
查看原文
由于组合计数水平过低连黄题都切不掉了QWQ,故作此笔记。

1. 组合数的一些公式

  • 排列数:

    即从nn个元素中,选取mm个元素进行排列(按一定顺序),记作Anm(mn)A_n^m (m \le n)
    有计算公式: Anm=n!(nm)!A_n^m=\frac{n!}{(n-m)!}
  • 组合数:

    即从nn个元素中,选取mm个元素(无顺序),记作Cnm(mn)C_n^m (m \le n),当然(nm)\begin{pmatrix}n \\ m \\ \end{pmatrix}也可以。
    有计算公式: Cnm=AnmAmm=n!m!(nm)!C_n^m=\frac{A_n^m}{A_m^m}=\frac{n!}{m!(n-m)!}
    大家都会推就不说为什么了。
    当然,这东西公式和性质挺多的,以下是一些性质。
  • 对称性:

    因为组合数,选取元素时选择补集是等价的,所以有: Cnm=CnnmC_n^m=C_n^{n-m}
  • 递推式:

    这个公式其实可以等价于杨辉三角的公式表达,所以有: Cnm=Cn1m+Cn1m1C_n^m=C_{n-1}^{m}+C_{n-1}^{m-1}
  • 二项式定理:

    对于表达式(a+b)n(a+b)^n,它的展开式与组合数仍脱不开关系,有等式: (a+b)n=i=0n(nm)aibni(a+b)^n= \sum_{i=0}^{n}\begin{pmatrix}n \\ m \\ \end{pmatrix}a^{i}b^{n-i}
    a=1,b=1a=1,b=1,等式就变成了i=0nCni=2n \sum_{i=0}^{n}{C_n^i}=2^n
    a=1,b=1a=1,b=-1,等式就变成了i=0n(1)iCni=0,(n0) \sum_{i=0}^{n}{(-1)^i}{C_n^i}=0,(n \ne 0)
  • 范德蒙恒等式:

    很高级的名字,可以用来拆解组合数,等式为: i=0kCniCmki=Cn+mk \sum_{i=0}^{k}C_n^iC_m^{k-i}=C_{n+m}^k
    怎么来的,这里可以用二项式定理证明:
    对于(1+x)n(1+x)m(1+x)^n(1+x)^m,将左右式展开再相乘其中xkx^k项的系数为i=0kCniCmki\sum_{i=0}^{k}C_n^iC_m^{k-i},(即左边xix^i项系数乘以右边xkix^{k-i}项)。
    对于(1+x)n+m(1+x)^{n+m},直接套用二项式定理,其xkx^k项系数为Cn+mkC_{n+m}^k
    注意到(1+x)n+m=(1+x)n(1+x)m(1+x)^{n+m}=(1+x)^n(1+x)^m,所以上式得证。
    对了,这东西有个特殊情况:令n=mn=m,则有i=0kCniCnki=C2nk\sum_{i=0}^{k}C_n^iC_n^{k-i}=C_{2n}^k
  • 多重组合数&多重集的排列:

    这是什么?
    对于一个多重集,SkS_k里面有个kk种元素,第ii个元素有nin_i个(同种元素无顺序),同时满足i=1kni=n\sum_{i=1}^{k}n_i=n,现在对这个集合进行排列,有多少种方案。
    有公式:
    n!i=1kni!\frac{n!}{\prod_{i=1}^{k}n_i!}
    怎么来的?先不管相同的元素,元素一共有nn个,所以一共有n!n!个方案,但对于第ii个元素,内部的nin_i个元素,它是无序的,所以把内部的ni!n_i!个重复的方案除去就行了。
  • 容斥原理:

    引入:

    还记得那个初中思维题吗?有三个比赛项目,9人报名了游泳,7人报名了跑步,5人报名了羽毛球,有多少人报名了项目? 其实还有数据,懒得打了
    其实这题不难,用集合表示就是,AA为报名游泳的人,BB为报名跑步的人,CC为报名羽毛球的人。对着图分析会发现,答案就是:
    ABC=A+B+CABACBC+ABC|A \cup B \cup C|=|A|+|B|+|C|-|A \cap B|-|A \cap C|-|B \cap C|+|A\cap B \cap C|
    这就是容斥。

    基本概念:

    那么对于nn个比赛项目,我们也可以用类似的方法推导,但在这之前,我们得先引入几个概念。
    全集UU,表示满足问题可能出现的所有情况。
    元素xx,对于题设下的一种方案。
    性质PiP_i,元素所要满足的条件,同时设满足PiP_i性质的元素构成集合SiS_i
  • 多重组合数:

2.一些常见问题

  • 错排问题

    问题描述:对于一个长度为nn排列 pp,我们要求 piip_i\ne i 求可行的方案个数。

    问题解析:先扔公式,我们定义用nn个元素时的方案个数为DnD_n Dn=(n1)(Dn1+Dn2)D_n=(n-1)(D_{n-1}+D_{n-2}) 怎么来的?用递推就行了。 对于第nn个元素,有n1n-1个位置选择放。
    那我换掉的那个元素怎么办?分讨!
    对于换掉的元素kk
    (1)(1)kk放在位置nn,那么对于除外的n1n-1个元素,由于kk放在了位置nn,所以剩下的元素就是相当于做一个错排,所以这里有Dn2D_{n-2}中情况。
    (2)(2)当元素kk不放在位置nn,这时等同于pnkp_n\ne k所以这相当于算上kk的错排,这时有Dn1D_{n-1}种放法。
    这时候,将kk的情况加在一起,然后和nn的情况相乘,递推式就出来了。
  • 不相邻排列

    问题描述: 对于nn个元素,从中选出kk不相邻的元素的方案个数。
    问题解析: 因为元素间除了位置全部相等,所以可以将元素分类

    1.1.我选出来的元素,有kk个;

    2.2.没被选出来的元素,有nkn-k个。

    既然我们只关心选走的是第几个,所以可以利用插板法,一共有nk+1n-k+1个空位,选择kk(不可以相邻)个位置放置选出来的元素,可以得出一共有Cnk+1kC_{n-k+1}^k个方案。
  • Prüfer序列

    问题描述:先看看这题
    问题解析:问题中描述的节点度数,还是太恶心了点,所以有没有一个可以快速计算带标号树种类数的东西。
    有的有的,兄弟有的,Prüfer 序列就可以帮你解决这个问题。
    这东西是什么?
    首先规定有一个节点标号为 [1,n][1,n]。的无根树,比如这个:
    • 第一步:找到一个编号最小的叶子节点,比如 11 号。
    • 第二步:然后把它删除。
    • 第三步:同时把与它连接的节点放在序列的末尾。
      然后重复下列操作。
      序列的构造就会像是 {2}{2,2}{2,2,3}{2,2,3,3}{2,2,3,3,2}\{ 2 \} \to \{2,2\} \to \{2,2,3\} \to \{2,2,3,3 \} \to \{2,2,3,3,2\}
      咦?怎么不往下构造了?因为只剩两个节点时,再往下构造其实就没啥意义了。
      好!哪这个东西有什么用呢?这个序列呢,一看就非常有性质,而在OI圈里,一个有性质的东西,那就有操作空间了。
      拿它有什么性质呢?
      1.1. 每个结点在序列中出现的次数是其度数减 11。(没有出现的就是叶结点)
      2.2. 在构造完 Pru¨ferPrüfer 序列后原树中会剩下两个结点,其中一个一定是编号最大的点nn
  • 一类线性不定方程的解组数

    问题描述:对于方程x1+x2+x3++xk=nx_1+x_2+x_3+ \dots +x_k=n其中xx为正整数,求解的组数。
    问题解析:问题可以变一下,求nn个完全相同的元素,将其分为kk组,保证每组至少有一个元素,一共有多少种分法?
    因为元素完全相同,我们可以将问题抽象化。这其实不就是用k1k-1块板子将nn个元素隔开吗?(从左到右,k1k-1块板子将元素分成了kk组,而这就是我们要的那kk组元素。)
    一共有n1n-1个空位,k1k-1块板子,所以答案就是Cn1k1C_{n-1}^{k-1}
    问题扩展:如果xx为非负整数呢?
    显然,这相当于每组可以没有元素,这时再用上面的方法就不行了。但如果我先给每组都“借”一个元素并放进去,是不是相当于每个xx此时都一定不为00了,这时候,和上面不就相同了吗。 所以答案就是Cn+k1k1C_{n+k-1}^{k-1}
    不难注意到,这个其实就是可重复选择元素的选择公式。
    其实还有一个严谨的方法,令ti=xi+1,(ti1t_i=x_i+1,(t_i \ge 1),再代入方程,得。
    i=1kxi=i=1k(ti1)=n \sum_{i=1}^{k}x_i= \sum_{i=1}^k(t_i-1)=n
    i=1kti=n+k \sum_{i=1}^kt_i=n+k
    这时,你就会发现这个方程,和一开始的问题不就一样了吗?所以套公式就行了。
    问题再扩展:到这,就完了吗?显然,还可以在普遍一些。我们规定第ii组至少有aia_i个元素。这回怎么办?其实观察“问题扩展”中,我们将问题同化的做法,我们也可以将这个问题转化为基础情况。 设ti=xiait_i=x_i-a_i,代入方程得。 i=1kxi=i=1k(ti+ai)=n\sum_{i=1}^{k}x_i= \sum_{i=1}^{k}(t_i+a_i)=n
    i=1kti=ni=1k(ai)\sum_{i=1}^{k}t_i=n- \sum_{i=1}^{k}(a_i)
    这时候,观察方程,发现和扩展的问题等价,所以答案为
    Cnai1k1C_{n-\sum a_i-1}^{k-1}
    其实,将没见过的问题可以尝试利用见过的问题去解释,或者变换为见过的问题,是个不错的方法。

3.一些例题

1.P6475 [NOI Online #2 入门组] 建设城市

题目分析
观察题目,注意到题目中的x,yx,y 两座楼可以在同侧,也可以在异侧,所以要先对大前提分讨。同时注意到值域m[1,105]m \in [1,10^5] 所以可以枚举地标高度。
  • Case1:xn<yx \le n < y 时,同时假设地标高度为hh
    此时xxyy 在“顶峰”的两侧,两座地标将城市分成了4段区间:
    • [1,x1][1,x-1] 这一段高度范围为 [1,h][1,h]
    • [x+1,n][x+1,n] 这一段高度范围为 [h,m][h,m]
    • [n+1,y1][n+1,y-1] 这一段高度范围为 [h,m][h,m]
    • [y,2n][y,2n] 这一段高度范围为 [1,h][1,h]
    你会发现在这几个区间内,我们要解决的是一个相同的子问题。即[l,r][l,r]区间内,元素值域为[1,h][1,h] 且元素值具有单调性的的赋值方案数。
    先不管元素的顺序,先取出一个有rl+1r-l+1 个元素的集合,这相当于从hh 个元素中可重复的选出rl+1r-l+1 个元素,这时,你就会发现,每个集合都对应着一个有单调性的方案(就是将这个集合排序),所以,方案数就是: Ch+rlhC_{h+r-l}^h 综上,对于一个确定的hh ,方案总数就是四段区间的方案相乘(乘法原理)。
  • **Case2:**当x<ynx<y \le n n<x<yn < x <y 时,同时假设地标高度为hh
    此时,x,yx,y 在中心的同一侧,那没有地标的一侧方案数一定,那利用与 Case1一样的方法进行区间划分,在相乘即可。
总结: 对于问题,合理的将问题拆解,进行分类讨论或是分步计算,利用计数原理统计计数。
Code
C
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=3e5+7;
const int mod=998244353;
int fastpow(int x,int n){
	int res=1;
	while(n){
		if(n&1) res=res*x%mod;
		x=x*x%mod,n=(n>>1);
	}
	return res;
}
int inverse(int x) {return fastpow(x,mod-2);}
int fac[N];
void init() {fac[0]=1;for(int i=1;i<N;i++) fac[i]=fac[i-1]*i%mod;}
int C(int n,int m){//C_n^m
	return fac[n]*inverse(fac[m])%mod*inverse(fac[n-m])%mod;
}
int n,m,x,y;
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	init();
	cin>>m>>n>>x>>y;
	int res=0;
	if(x<=n&&n<y){
		for(int i=1;i<=m;i++){
			int a=C(x-1+i-1,x-1)*C(m-i+1+n-x-1,n-x)%mod,b=C(y-1-n+m-i+1-1,y-1-n)*C(2*n-y+i-1,2*n-y)%mod;
			res=res+a*b%mod;
		}
	}else{
		if(x>n&&y>n) x=x-n,y=y-n;
		for(int i=1;i<=m;i++){
			int a=C(x-1+i-1,x-1)*C(n-y+m-i,n-y)%mod;
			res=(res+a)%mod;
		}
		res=res*C(n+m-1,n)%mod;
	}
	cout<<res%mod<<"\n";
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...