数论部分知识整理

组合数的若干求法

组合数计算式:

\[\binom{n}{m}=\frac{n!}{m!\times (n-m)!} \]

  • 预处理阶乘和逆元

    \[\binom{n}{m}=fac_m\times inv~fac_n \times inv~fac_{n-m} \]

    要边乘边模,不然会爆。。

    模数不是质数不能用,因为没有逆。

    最坏复杂度 \(O(n+log~p)\)

  • 杨辉三角

    \[\binom {n}{m}=\binom{n-1}{m}+\binom{n-1}{m-1} \]

    注意边界情况。

    C[0][0] = C[1][0]=c[1][1]=1;
    for (int i = 2; i <= max; ++ i) {
        c[i][0] = 1;
        for (int j = 1; j <= i; ++ j)
            c[i][j] = (C[i-1][j-1]+c[i-1][j]) % p;
    }
    
  • \(Lucas\) 定理

    \[\binom {n}{m}=\binom{n\bmod p}{m\bmod p}\times \binom{n/p}{m/p}\bmod p \]

int C (int a, int b) {...}
int Lucas (int a, int b, int p) {
    if (b > a) return 0;
    return C (a % p, b % p) * Lucas (a / p, b / p) % p;
}

luogu P2606 排列计数

题目描述

称一个 \(1 \sim n\) 的排列 \(p_1,p_2, \dots ,p_n\) 是 Magic 的,当且仅当

\[\forall i \in [2,n],p_i > p_{\lfloor i/2 \rfloor} \]

计算 \(1 \sim n\) 的排列中有多少是 Magic 的,答案可能很大,只能输出模 \(m\) 以后的值

能看出 Magic 序列与二叉树的形式很像。

所以这个题就转化成了能构成多少种满足 \(val_{son} > val_{fa}\) 的树。

因为每个节点的左右儿子相互独立,所以不需要考虑左右儿子之间的关系,满足 dp 的性质,可以树形 dp。

每个节点产生的答案就是 \(C(siz[lson] + siz[rson], siz[lson])\),可以理解为,现在剩余 \(siz[x] -1\) 个数,要分给左右儿子,其中分给左儿子 \(siz[lson]\) 个数字。

哇!我要切蓝题了!交一发,wa了一片……

为什么呢,看数据范围,并不保证模数大于 \(n\)。所以我们需要 Lucas 定理求组合数。

最后这个题就是,树形 dp + Lucas 求组合数。

int Lucas (int a, int b) {
	if (!b) return 1;
	return 1LL * C (a % m, b % m) * Lucas (a / m, b / m) % m;
}
int getsiz (int x) {
	siz[x] = 1;
	if (x * 2 <= n) getsiz (x * 2);
	if (x * 2 + 1 <= n) getsiz (x * 2 + 1);
	siz[x] += siz[x * 2] + siz[x * 2 + 1];
}
int dfs (int x) {
	if (x > n) return 1;
	return 1LL * Lucas (siz[x] - 1, siz[x * 2]) * dfs (x * 2) % m * dfs (x * 2 + 1) % m;
}

欧拉函数的若干求法

\(\varphi(n)\) 表示小于 \(n\) 的所有数中,与 \(n\) 互质的数的个数。

  • 根据定义质因数分解

    每次找到一个质因子,在答案里减去 \(n\) 中包含这个质因子的倍数的个数,即 \(n-\frac{n}{i}\),也可以写成 \(\frac{n*(i-1)}{i}\)

int eul_phi (int n) {
	int re = n;
	for (int i = 2; i * i <= n; ++ i)
		if (n % i == 0) {
			re = re / i * (i - 1);
			while (n % i == 0) n /= i;
		}
	if (n > 1) re = re / n * (n - 1);
	return re;
}
  • 筛法求欧拉函数

    线性筛中,通过枚举质数的倍数工作,这恰恰与欧拉函数不谋而合 qwq,所以我们可以通过筛法求。

    \(p_1\)\(n\) 的最小质因子,\(n'=\frac{n}{p_1}\),所以 \(n\) 是被 \(n'\times p_1\) 筛掉的。

    跑筛法的时候要处理两种情况。

    1. 如果 \(n’ \bmod p_1 = 0\)\(n'\) 包含了 \(n\) 的所有质因子。

      \[\varphi(n)=n\times \prod_{i=1}^s\frac{p_i-1}{p_i}\\ =p_1\times n'\times \prod_{i=1}^s\frac{p_i-1}{p_i}\\ =p_1\times \varphi(n') \]

    2. 如果 \(n' \bmod p_1 \neq 0\)\(n'\)\(p_1\) 互质,根据欧拉函数的性质

      如果 \(gcd (a, b) = 1\),那么 \(\varphi (n) = \varphi(a) \times \varphi (b)\)

void work () {
	phi[1] = 1;
	for (int i = 2; i <= max; ++ i) {
		if (!numlist[i]) {
			prime[++ cnt] = i;
			phi[i] = i - 1;
		}
		for (int j = 1; j <= cnt && i * prime[j] <= max; ++ j) {
			numlist[i * prime[j]] = 1;
			if (i % prime[j])
				phi[i * prime[j]] = phi[i] * prime[j];
			else {
				phi[i * prime[j]] = phi[i] * phi[prime[j]];
				break;
			}
		}
	}
}
posted @ 2022-08-29 20:21  zcxxxxx  阅读(27)  评论(0编辑  收藏  举报