解题套路
从 1,2,…,n 里取 k 个数,记从小到大是 a1<a2<⋯<ak。换一组变量:
u0=a1−1,ui=ai+1−ai−1 (1⩽i⩽k−1),uk=n−ak.
它们全部 ⩾0,而且
u0+u1+⋯+uk=n−k.
这是一一对应:给一组非负整数解,令 a1=u0+1、ai+1=ai+ui+1 就还原出唯一一个取法。于是
「取 k 个数」的方案数 = 方程 u0+⋯+uk=n−k 的非负整数解个数 =Cnk,
隔板法算出来的正是 C(n−k)+kk=Cnk——先用这条自洽检查确认换元没写错,再往下用。
关键在于,条件全都翻译成了对 ui 的下界:
| 原来的说法 | 换元之后 |
|---|
| ai 与 ai+1 相邻 | ui=0 |
| ai 与 ai+1 不相邻 | ui⩾1 |
| 两两不相邻 | u1,…,uk−1 全 ⩾1 |
| 首项不取 1 | u0⩾1 |
下界一律用「预扣」消掉:要求 ui⩾1 就令 ui′=ui−1,右端的总量相应减 1,方程重新变成一个纯粹的非负整数解问题。
用起来是什么样
从 1∼9 里取 3 个数(n=9、k=3),u0+u1+u2+u3=6:
- 两两不相邻(u1,u2⩾1):预扣两个,u0+u1′+u2′+u3=4,解数 C4+33=C73=35。
- 三个连号(u1=u2=0):u0+u3=6,解数 C6+11=7。
- 恰有一处相邻(u1、u2 恰有一个为 0):两支对称,每支 u0+u′+u3=5,解数 C5+22=21,共 42。
三堆加起来 35+7+42=84=C93 ✓——同一个动作做三遍,而不是三种互不相干的技巧。
什么时候想到它
- 条件是相邻 / 不相邻 / 间隔至少几个这一类(它们全是对 ui 的下界);
- 要的不是一个数,而是按「有几处相邻」分类的整张表——正面数要分好几类,换元之后是同一套动作;
- 插空法只回答「两两不相邻有几种」,这条路把「恰好有几处相邻」也一并回答了。
边界
- 只对「从一列里按大小取」有效。 取出来还要排顺序的,另乘 Akk;元素本身有区别(不是位置)的,这条换元无从谈起。
- 两端的 u0、uk 与中间的 ui 意义不同:中间那些管相邻,两端那两个只管靠不靠边。别把两端也顺手加上 ⩾1。
- 换元后先做一次自洽检查(无约束时解数必须等于 Cnk)。这一步花不了几秒,却能挡住「右端写成 n−k+1」这种最常见的手滑。