数论组合数

· · 个人记录

组合数

C_n^m=\dfrac{n!}{m!(n-m)!} C^m_n=C_{n-1}^{m-1}+C_{n-1}^m \sum_{i=0}^nC_n^i=2^n $\sum_{i=0}^n k\times C_n^k=n\times 2^{n-1} \sum_{i=0}^n k^2\times C_n^k=n\times (n-1)\times 2^{n-2}
  1. 递推

  1. 预处理 N 以内的阶乘 fact_i阶乘的逆元

逆元递推式:inv_i=inv_{i+1}\times (i+1)

C_n^m=fact_n\times inv_m\times inv_{n-m}

复杂度 O(n+\log_2 p)

注:模数必须为质数

  1. 玄学,玄学,还是玄学

可以对模数 p 分解质因数,对于每个 i 及每个质因数 pr_j,预处理出每个 i! 所包含的 pr_j 的数量记为 r_{i,j}

我们来处理一下以下柿子:

\dfrac{n!}{m!} =\dfrac{k\times pr_1^{x_1}\times pr_2^{x_2}....}{s\times pr_1^{y_1}\times pr_2^{y_2}....} =k\times inv_s\times pr_1^{x_1-y_1}\times pr_2^{x_2-y_2}....

由于 k,s 中已经不包含任意的 p 的质因子了,所以 \gcd(k,p)=1,\gcd(s,p)=1

这就意味着存在 inv_s\times s\equiv 1\pmod p

可以预处理出 fact_nfact_n 除去 p 的所有质因子后的逆元 inv_n,之后直接按照上述式子计算即可。

复杂度 O(n\log_2 n),但是常数。

注:不要求模数为质数

思路:对于大质数 p 分解质因数,转化为

C_n^m\equiv a_i\pmod {pr_i}

其中 a_i=\dfrac{n!\bmod pr_i^{r_i}}{m!\bmod pr_i^{r_i}\times (n-m)!\bmod pr_i^{r_i}}

其中 n!\bmod p^k

=((p^k-1)!)^{n/p}\times (n/p)!\times (n\bmod p)!

注:这里的 ! 不带有 p 的倍数;(n/p)! 除外,它需单独计算

n!,m!,(n-m)! 组合起来即可

void init(int p,int pk)
{
    fac[0]=1;
    for(int i=1;i<=pk;i++)
    {
        fac[i]=fac[i-1];
        if(n%p)fac[i]=fac[i]*i%pk;
    }
}
int fir(int n,int p,int pk)
{
    if(n==0)return 1;
    int res=qm_n(fac[pk],n/pk,pk);
    return res*fac[n%pk]%pk*fir(n/p,p,pk)%pk;
}
int sec(int n,int p)
{
    if(n==0)return 0;
    return n/p+sec(n/p);
}
void come_on(int n,int m,int p,int pk)
{
    int k1=fir(n,p,pk);
    int k2=inv(fir(m,p,pk),pk);
    int k3=inv(fir(n-m,p,pk),pk);
    int other=qm_n(p,sec(n,p)-sec(m,p)-sec(n-m,p),pk);
    return k1*k2%pk*k3%pk*other%pk;
}
void exlucas(int n,int m,int p)
{
    //对 p 分解质因数,a[i]=come_on(n,m,pr_i,pr_i^r_i),b[i]=pr_i 
    int res=1,x;ans=0;
    for(int i=1;i<=cnt;i++) res*=b[i];
    for(int i=1;i<=cnt;i++) x=inv(res/b[i],b[i]),ans=(ans+x*(res/b[i])%p*a[i]%p)%p;
    //CRT
}//int128

可重集

1. 组合,数量无限: 考虑插板法,在 $n-1$ 个空位之中插入 $m-1$ 个板子 2. 组合,数量有限 考虑容斥,设第 $i$ 类不满足要求,可以预分配 $a_i+1$ 个 状压或深搜枚举不满足要求的 $i$,根据奇偶性容斥 其余皆按无限处理 3. 排列,数量有限 $\dfrac{n!}{\prod_{i=1}^m (a_i!)}
  1. 排列,数量无限

卡特兰数

指一类序列,为

1,1,2,5,14,42,132,429....

卡特兰数有许多模型:

  1. 走格子模型:
2. 括号序列:给定 $n$ 对括号求合法的括号序列数 3. $n+2$ 边形拆分问题 4. 买票找零问题 5. $n$ 个节点的无标号二叉树 卡特兰数有两种计算方式: 1. $C_{n+1}=\sum_{i=0}^n C_i\times C_{n-i}

代表模型:多边形拆分

  1. C_{n}=C_{2n}^n-C_{2n}^{n-1}

代表模型:走格子

走格子推导过程:

其实这条黑线不一定要是对角线

设黑线在第一象限内与 xy 轴的交点距原点 k

则答案为 C_{2n}^n-C_{2n}^{n-k-1}

球与盒子

主要有两个表: $\color{red}empty:$ $\ $ **1. 球的排列有影响 2. 球的排列无影响** **1. 盒子的排列有影响** $\ $ $m^n\qquad C_{n+m-1}^{m-1}

2. 盒子的排列无影响 \ \sum_{i=0}^m s2(n,i) \ \sum_{i=0}^m P(n,i) |

**3. 盒子的排列有影响** $\ $ $m!\times s2(n,m)\quad C_{n-1}^{m-1}

4. 盒子的排列无影响 \ s2(n,m) \quad P(n,m)

  1. (3,4)

经典插板法,问题可以转化为这样:

上图即为 n=7,m=4 的情况。

问题转化为了在 n-1 个空位中插入 m-1 个木板,就可以将 n 个球分成 m 份,求方案数。

即为 C_{m-1}^{n-1}

如果是 (1,2)(即可空),我们可以对于每个盒子预分配一个球,即多出 m 个球,按照上述方法计算即可。

事实上,这种模型也可以使用插板法:

_求 x_1+x_2+....+x_n=m 的正整数解的个数。_

这种情况下可以把 m 拆分为 m 个 1,即 m 个“球”,再插入 n-1 个木板,第 i 与第 i+1 块木板之间的 1 之和即为 x_{i+1}

    • s2 是什么

有一个明显的递推式:s2(n,m)=s2(n-1,m-1)+m\times s2(n-1,m)

考虑新加入一个球,这个球可以单独放入第 m 个盒子即 s2(n-1,m-1)

也可以放在前面的盒子当中。

前面的 n-1 个球已经分配给了 m 个盒子,所以有 m 个放的地方,就是 m\times s2(n-1,m)

其实我们可以联系上 (3,3)

找规律可以发现,(3,3)(4,3) 差了一个 m!

(3,3) 就是这玩意。

而这个玩意儿可以使用容斥,枚举缺失了几个数来解决,有

m!\times s2(n,m)=\sum_{i=0}^m (-1)^i\times C_m^i\times (m-i)^n $n$ 个位置可以任意取剩下的 $m-i$ 个数,即为 $(m-i)^n$。 所以 $s2(n,m)$ 可以用上述式子除上一个 $m!$ 得到,总时间复杂度 $O(m\log_2 n)$。 实际上,$(m-i)^n$ 甚至可以使用线性筛预处理,虽然不能完全 $O(m)$,但是常数比 $O(m\log_2 n)$ 小得多。 - $Bell$ 数 这玩意儿其实就是 $\sum_{i=0}^n s2(n,i)$。 它可以理解为把 $1,2,3,....$ 划分为 $m$ 个子集。 它有另外一个递推式: $Bell_{n+1}=\sum_{i=0}^n C_n^i\times Bell_i$。 ~~感性理解一下~~ 关于这玩意儿,还有一个更离谱的东西: ![](https://cdn.luogu.com.cn/upload/image_hosting/u7pow91e.png) 它每行的第一个数和最后一个数都是 $Bell$ 数。 - 第一类斯特林数 它与前文提到的那玩意有什么区别呢? 第一类($s1$)是⚪排列,$s2$ 是普通排列。 这就导致它的递推不一样: $s1(n,m)=s1(n-1,m-1)+(n-1)$ (即为可以插入的位置的个数,在 $s1$ 里一个球即使被放入同一个盒子,位置不同也算作不同方案) $\times s1(n-1,m)$。 3. $(4,4)

什么是 P

它可以理解为把一个自然数 n 拆分成 m 个数的方案。

有递推式:

P(n,m)=P(n-1,m-1)+P(n-m,m) $P(n-m,m)$ 表示将之前 $n-m$ 分成 $m$ 块的所有方案中的所有数都加一个 1,加了 $m$ 个数然后块数不变 如果我们把 $n$ 分成任意块数,即自然数分解,答案就是 $\sum_{i=0}^m P(n-i)