组合数学

组合基础与数论基础

组合数

Lucas 定理

n,m,N,nm,pP,(nm)(n/pm/p)(nmodpmmodp)(modp)

证明:

引理:pP,n[1,p1]Z,(pn)0(modp)

pP,(px)p!x!(px)!p(p1)!x!(px)!0(modp)。证毕。

(1+x)pi=0p(pi)xi1+i=1p1(pi)xi+xp1+xp(modp)

{qn=nprn=nmodpqm=mprm=mmodp,由取模定义可知 {qnp+rn=nqmp+rm=m

(1+x)n(1+x)qnp+rn(1+x)qnp(1+x)rn(1+xp)qn(1+x)rn(i=0qn(qni)xip)(i=0rn(rni)xi)i=0qnj=0rn(qni)(rnj)xip+j

(1+x)n=i=0n(ni)xi

所以 i=0n(ni)xii=0qnj=0rn(qni)(rnj)xip+j(modp)

k=ip+j,因为 0j<rn,所以 i=kp,j=kmodp

i=0n(ni)xii=0qnj=0rn(qnkp)(rnkmodp)xk(modp)

因为 nm,则对于左式有 i=m 时,右式有 k=m 时,即有 (nm)xm(qnmp)(rnmmodp)xm(modp),因为 {qn=nprn=nmodp,即得 (nm)(npmp)(nmodpmmodp)(modp)。证毕。

扩展Lucas exLucas

给定正整数 n,m,P,1mn1018,1P106,求

(nm)modP

exLucasLucas 定理并无多大关系,exLucas 我认为是一种算法。

学习 exLucas 之前建议看看阶乘质因数分解

P 不为质数,将 P 质因数分解 P=pici

(nm) 对每个 pc 取模,得出若干同余方程,利用中国剩余定理求出答案:

{(nm)a1(modp1c1)(nm)a1(modp1c1)(nm)a1(modp1c1)(nm)a1(modpwcw)

关键在于计算 (nm)modpc

(nm)=n!m!(nm)!(modpc)

有除法,但是 m!(nm)! 不一定和 pc 互质,即可能无法求出其逆元。

一个方法是将 m!(nm)! 的因子 p 都除去,使之与 pc 互质:

n!m!(nm)!n!pxm!py(nm)!pzpxyzx 就是 n! 质因数分解后 p 的指数,y,z 同理。


n!=1×2×3××nn 个数当中有 np 个数是 p 的倍数,因为每 p 个数就有一个数是 p 的倍数。

n!=np!p1inpiinp! 里可能有 p 的倍数,可以递归地来求。

f(n)=n!pxmodpc,有 f(n)=f(np)1inpiimodpc,没有 ×p 的原因是分母是 pxp 都被约掉了。

1inpii=(npc+1inpii)(0inpc11jpcpj(ipc+j))(modpc)

发现 ipc+jj(modpc)

1inpii(npc+1piini)(0inpcpc1i1jpcpjj)(npcpc+1piini)(1jpcpjj)npc(modpc)

f(n)=f(np)(npcpc+1piini)(1jpcpjj)npc(modpc)

调用一次 f 的时间复杂度为 O( 递归次数 ×( 积式 + 快速幂 ))=O(logpn(pc+log2npc))=O(pclog+log2)


现在问题在于求 x,y,z

g(n)=x,有 g(n)=g(np)+np

n!=1×2×3××n,这 n 个数中是 p 的倍数显然有 np 个,将这 np 个数 ×1p 在相乘可得 np!,即 g(np),所以 g(n)=g(np)+np


综上,exLucas 有以下步骤:

  1. 质因数分解 P=pici,时间复杂度 O(P),但是有效 pici 最多有 O(7)

  2. 计算 (nm)modpici,时间复杂度 O(pclog+log2)

    (nm)=n!pxm!py(nm)!pzpxyzf(n)f(m)1f(nm)1pg(n)g(m)g(nm)(modpc)

  3. 用中国剩余定理求出方程组的解,即为答案。时间复杂度 O(7logn)

步骤 2. 的 pc 最坏为 P

关于 1. 3. 时间复杂度为什么和 7 有关,因为方程的个数即为 P 不同质因数的个数,最坏情况为 P=2×3×5×7×11×13×172×3×5×7×11×13×17×19>106

1.2. 是嵌套关系,1.2. 执行完执行 3. ,则总时间复杂度为 O(P+7(Plog+log2)+7logn)=O(P+Plog)

例题 SDOI2010古代猪文

Luogu SDIO2010古代猪文

给定整数 q,n1q,n109,计算

qd|nCndmod999911659

q=999911659,则答案为 0

q999911659,根据欧拉定理推论有:qd|nCndqd|nCndmod999911658(mod999911659)

关键在于计算 d|nCndmod999911658,模数不是质数,不能应用 Lucas 定理,尝试将其质因数分解。

999911658=2×3×4679×35617,这样的数为 square-free-number,它的所有质因子质数都是 1。设 x=Cnd,用这四个质因数分别运用 textLucas 定理给 x 取模,可得:

{xa1(mod2)xa2(mod3)xa3(mod4679)xa4(mod35617)

用中国剩余定理求出 x,然后用快速幂求出 qxmod999911658,即可。

时间复杂度为 O(快速幂 + 求因数 ×(Lucas 定理 + 中国剩余定理))=O(log+n(log+log))=O(nlog)

求法

(nm)modp,pP

方法 1:

通过 (nm)=(n1m)+(n1m1) 求组合数,时间复杂度 O(n2),回答时间复杂度 O(1)


方法 2:

预处理 0n 的阶乘和阶乘的逆元,时间复杂度 O(n),回答时间复杂度 O(1)


方法 3:

利用 Lucas 定理,预处理 0p1 的阶乘和阶乘的逆元,时间复杂度 O(p),回答时间复杂度 O(logp(n))


方法 4:

(nm),n5000,m5000,nm

注意,没有取模,需要用到高精度。

利用 (nm)=(n1m)+(n1m1) O(n2) 做貌似可以,但是要用到高精度,还有 O(n) 的位数,则时间复杂度 O(n3)

唯一分解即质因数分解

根据定义式 (nm)=n!m!(nm)! 来做,又因为组合数一定是个整数,所以我们用不到高精度除法,对分子和分母唯一分解,分子的每个质数的指数一定大于等于分母的对应指数,若小于则 m!(nm)! 不整除 n!,与组合数是整数矛盾。

综上步骤为:

  • n!,m!,(nm)! 唯一分解。
  • 约分,即用 (nm)!,m! 唯一分解出的质数消 n! 唯一分解出的质数。
  • 高精度 × 低精度

x! 质因数分解

代码实现:

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;


const int N = 5010;

int primes[N], cnt;
int sum[N];
bool st[N];


void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i]) primes[cnt ++ ] = i;
        for (int j = 0; primes[j] <= n / i; j ++ )
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) break;
        }
    }
}


int get(int n, int p) // 求n!中 质因子 p 需要累乘的次数 
{
    int res = 0;
    while (n)
    {
        res += n / p;
        n /= p;
    }
    return res;
}


vector<int> mul(vector<int> a, int b)
{
    vector<int> c;
    int t = 0;
    for (int i = 0; i < a.size(); i ++ )
    {
        t += a[i] * b;
        c.push_back(t % 10);
        t /= 10;
    }
    while (t)
    {
        c.push_back(t % 10);
        t /= 10;
    }
    return c;
}


int main()
{
    int a, b;
    cin >> a >> b;

    get_primes(a);//用欧拉筛筛出 [1~a] 范围内的质数 

    for (int i = 0; i < cnt; i ++ )
    {
        int p = primes[i];
        sum[i] = get(a, p) - get(a - b, p) - get(b, p); // C(a,b) 中第 i 个质数需要累乘的次数 
    }

    vector<int> res;
    res.push_back(1);

    for (int i = 0; i < cnt; i ++ ) // 枚举质因子 
        for (int j = 0; j < sum[i]; j ++ ) // 枚举当前质因子的个数 
            res = mul(res, primes[i]); // 做高精度乘低精度 

    for (int i = res.size() - 1; i >= 0; i -- ) printf("%d", res[i]);
    puts("");

    return 0;
}

一些基本式子

式子1

(nm)=(nnm)

证明:由定义即可得。

它的组合意义是从 n 个数中选 m 个数,与从 n 个数中选 nm 个数的方案数相同,相当于剩下 nm 个数不选。

式子2

(nm)=(n1m1)+(n1m)

证明:由定义即可得。

它的组合意义是 从 n 个数中选 m 个数的方案数 = 已经考虑了前 n1 个数,选择当前数的方案数((n1m1)) + 不选当前数的方案数 ((n1m)

它满足杨辉三角(帕斯卡三角)。

它可以看做一个递推式。

式子3

(nm)=nm(n1m1)

证明:由定义即可得。

式子4 二项式定理

nN,(x+y)n=i=0n(ni)xiyni

证明:

证法1:

数学归纳法。当 n=0 时,(x+y)0=1=i=00(0i)xiy0i,成立。

n=m 成立,现在证明 n=m+1 时成立:

(x+y)m+1=(x+y)(x+y)m=(x+y)i=0m(mi)xiymi=i=0m(mi)xi+1ymi+i=0m(mi)xiym+1i=i=1m+1(mi1)xiym+1i+i=0m(mi)xiym+1i=(mm)xm+1y0+(m0)x0ym+1+i=1m((mi1)+(mi))xiym+1i=(m+1m+1)xm+1y0+(m+10)x0ym+1+i=1m(m+1i)xiym+1i=i=0m+1(m+1i)xiym+1i=i=0n(ni)xiyni

证毕。

由二项式定理可以得出许多有用的式子:

  • i=0n(ni)=2n

    证明:将 (1+1)n 二项式展开即得。

    它的组合意义是,从 n 个数中选若干个数的方案数 = 从 n 个数中选 0 个数的方案数 + 从 n 个数中选 1 个数的方案数 + ... + 从 n 个数中选 n 个数的方案数。

  • i=0n(1)i(ni)=0

    证明:将 ((1)+1)n 二项式展开即得。

式子5

i=0n(m+ii)=(m+n+1m+1)

证明:

i=0n(m+ii)=i=0n(m+im)=(mm)+(m+1m)+(m+2m)+(m+3m)++(m+nm)=(m+1m+1)+(m+1m)+(m+2m)+(m+3m)++(m+nm)=(m+2m+1)+(m+2m)+(m+3m)++(m+nm)=(m+n+1m+1)

证毕。

不定方程整数解问题

问题1

mn,xi1,x1+x2+x3++xn=m

隔板法。

考虑有 m 个点,放入 n1 个隔板,将 m 个点分成 n 组点,每组点的个数为 xi 的值。

例如:m=10,n=3,有一种方案是:.|.......|..,这代表 x1=1,x2=7,x3=2

隔板显然不能放最左边和最右边,则 m 个点总共有 m1 个空可供 n1 个隔板放置,答案即为 (m1n1)

问题2

n,m,aixiai,x1+x2+x3++xn=m

考虑转换成问题1。换元 yi=xiai+1,原问题转化为求 yi1,y1+y2+y3++yn=m+(ai+1)的正整数解方案数,答案即为 (m+(ai+1)1n1)

问题3

nmxi1,x1+x2+x3++xnm

新添一个数 xn+1,xn+1=m1inxixi 没用完的都给 xn+1,原问题转化为求 xi1,x1+x2+x3++xn+xn+1m 的正整数方案数,答案即为 (m1n)

问题4

lnrxi1,lx1+x2+x3++xnr

拆成两个问题:

  1. xi1,x1+x2+x3++xnl1 正整数解方案数
  2. xi1,x1+x2+x3++xnr 正整数解方案数

2.的方案数 - 1.的方案数即为答案。

卡特兰数 Catalan

给定 n0n1,按某种顺序排成长度为 2n 的序列,满足任意前缀中 0 的个数都不少于 1 的个数的序列的数量为:

Catn=(2nn)n+1

Catn=i=1nCati1Catni+1,Cat0=1

证明:Catn=(2nn)n+1

n0n1 随意排列成一个长度为 2n 的序列 S,若 S 不满足任意前缀中 0 的个数都不小于 1 的个数,则存在一个最小的位置 2p+1[1,2n]Z,使得 S[12p+1] 中有 p0p+11。把 S[2p+22n] 中所有数字取反后,包含 np10np1。于是我们得到了由 n10n+11 排成的、存在一个前缀 01 多的序列。

同理。令 n10n+11 随意排列成一个长度为 2n 的序列 S,存在一个最小的位置 2p+1[1,2n]Z,使得 S[12p+1] 中有 p0p+11。把 S[2p+22n] 中所有数字取反后,我们得到了由 n0n1 排成的、存在一个前缀 01 多的序列。

因此,以下两种序列构成一个双射:

  1. n0n1 排成的、存在一个前缀 01 多的序列。
  2. n10n+11 排成的序列。

后者显然有 (2nn1) 个。

综上,由 n0n1,按某种顺序排成长度为 2n 的序列,满足任意前缀中 0 的个数都不少于 1 的个数的序列的数量为:

Catn=(2nn)(2nn1)=(2nn)n+1

证毕。(此证明摘自李煜东《算法竞赛进阶指南》)

证明:Catn=i=1nCati1Catni+1,Cat0=1

考虑序列 1,2,3,...,n 经过一个栈的合法出栈的方案数 fn

将进栈操作看做 0, 出栈操作看做 1,则 fn=Catn

对于当前数字 i1i1fi1 进出栈方案,i+1nfni+1 种进出栈方案,所以共有 fi1fni+1 种方案。对于所有数字有 fn=i=1nfi1fni+1 种方案。

综上 Catn=i=1nfi1fni+1

证毕。

与卡特兰数有关的问题

n 个左括号和 n 个右括号组成的合法括号序列的数量为 Catn

证明:将左括号看做 0,将右括号看做 1 即得。


n 个节点构成不同的二叉树的数量为 Catn

证明:设n 个节点构成不同的二叉树的数量为 fn,对于当前的节点 i1i1 节点放置的方案数为 fi1i+1n 节点放置的方案数为 fni+1,则 fn=i=1nfi1fni+1,符合 Catn,的式子。


在平面直角坐标系中,从 (0,0) 开始,每一步只能向上或向右走,走到 (n,n) 并且除两个端点外不接触直线 y=x 的路线数量为 2Catn1

证明:

第一步只能向上或向右走,就变成了两个本质相同的问题,所以答案 ×2

现在考虑第一步向右走,即从 (1,0) 点开始。设走一步的操作为 U、R,U 代表向上,R 代表向右,最后走到 (n,n) 点的操作一定形如 RRUURRU...,由 n1 个 U 和 n1 个 R 组成的串。为了不接触直线 y=x,操作一定满足任意前缀 R 的数量大于等于 U 的数量。将 R 看做 0,U 看做 1,答案即为 Catn1

容斥原理

摩根定律

A 为以 S 为全集 A 的补集。

AB=ABAB=AB

容斥原理

|i=1nAi|=J{1,2,3,,n}(1)|J|+1iJ|Ai|

例如 |AB|=|A|+|B||AB||ABC|=|A|+|B|+|C||AB||AC||BC|+|ABC|

|i=1nAi|=|S|J{1,...,n}(1)|J|+1|jJAj|=J{1,...,n}(1)|J||jJAj|

|i=1nAi|=|S|J{1,...,n}(1)|J|+1|jJAj|=J{1,...,n}(1)|J||jJAj|

多重集组合数

特殊情况

S={n1a1,n2a2,,nkak} 是由 n1a1n2a2nkak 组成的多重集。给定非负整数 ri,rni。从 S 中取出 r 个元素组成一个多重集(不考虑元素的顺序),可得的不同多重集的数量为:

(k+r1k1)

证明:

考虑不定方程。

设选了 xiai,则有方程 1ikxi=r,0xini,因为 rni,则一定满足 xini。原问题变成 1ikxi=r,0xi 的正整数解,这是不定方程整数解问题2,答案即为 (k+r1k1),证毕。

一般情况

S={n1a1,n2a2,,nkak} 是由 n1a1n2a2nkak 组成的多重集。给定非负整数 r。从 S 中取出 r 个元素组成一个多重集(不考虑元素的顺序),可得的不同多重集的数量为:

(k1k+r1)1ik(k+rni2k1)+1i<jk(k+rninj3k1)+(1)k(k+ri=1kni(k+1)k1)

(k1k+r1)S{1,2,3,,k}(1)|S|+1(k+riSni|S|1k1)

证明:

考虑不定方程。

设选了 xiai,则有方程 1ikxi=r,0xini

先不考虑 xini 的限制,0xi 的方案数为 (k1k+r1),然后再减去不合法的方案。

不合法的方案为 xi,xini的方案。于求不合法的方案:

xana,则限制变为 xana,0xi,(ia),这是不定方程整数解问题2,答案即为 (k+rna2k1)

ab,xana,xbnb,则限制变为 xana,xbnb,0xi,(ia,ib),这是不定方程整数解问题2,答案即为 (k+rnanb3k1)。上一种包含含这种情况,所以要减去。

以此容斥。

最中得到 (k1k+r1)S{1,2,3,,k}(1)|S|+1(k+riSni|S|1k1)

证毕。

本文作者:kuailedetongnian

本文链接:https://www.cnblogs.com/kuailedetongnian/p/18522256

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   kuailedetongnian  阅读(49)  评论(1编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起