一个整数可以被表示成若干质数的乘积。例如:\(48=2^4 \times 3, \ 49 = 7^2, \ 50 = 2 \times 5^2\)。
算术基本定理:设 \(a>1\),那么必有 \(a = p_1^{\alpha_1} p_2^{\alpha_2} \cdots p_s^{\alpha_s}\),其中 \(p_i \ (1 \le i \le s)\) 是两两不相同的质数,\(\alpha_i \ (1 \le i \le s)\) 表示对应质数的幂次。
朴素的分解质因数的时间复杂度和枚举约数一样都是 \(O(\sqrt{n})\)。
int decomposition(int x) {
// 分解x,数组a记录所有质数,返回分解出来的质数数量
int cnt = 0;
for (int i = 2; i <= x / i; i++) {
while (x % i == 0) {
a[++cnt] = i;
x /= i;
}
}
if (x > 1) a[++cnt] = x;
return cnt;
}
算术基本定理是处理整除性和数论函数的有力工具。
假定 \(a = p_1^{\alpha_1} p_2^{\alpha_2} \cdots p_s^{\alpha_s}\),有以下推论:
推论:\(d\) 是 \(a\) 的约数的充要条件是 \(d = p_1^{e_1} p_2^{e_2} \cdots p_s^{e_s}, \ 0 \le e_i \le \alpha_i, \ 1 \le i \le s\),即 \(d\) 中每个质数的幂次都不超过 \(a\)。
每个质因子上的幂次直接决定了两数之间的整除性。
例如 \(12 = 2^2 \times 3, \ 72 = 2^3 \times 3^2\),\(12\) 的每个质因子上的幂次都对应地不超过 \(72\) 的,因此 \(12 | 72\)。
推论:若 \(b = p_1^{\beta_1} p_2^{\beta_2} \cdots p_s^{\beta_s}\),这里允许某些 \(\alpha_i\) 或 \(\beta_i\) 为零,那么 \((a,b) = p_1^{\delta_1} p_2^{\delta_2} \cdots p_s^{\delta_s}, \ \delta_i = \min (\alpha_i, \beta_i), \ 1 \le i \le s\),以及 \([a,b] = p_1^{\gamma_1} p_2^{\gamma_2} \cdots p_s^{\gamma_s}, \ \gamma_i = \max(\alpha_i, \beta_i), \ 1 \le i \le s\)。
比如,\(10 = 2 \times 5, \ 16 = 2^4\),那么 \((10,16) = 2^{\min(1,4)} \times 5^{\min(1,0)} = 2^1 \times 5^0 = 2\),且 \([10,16] = 2^{\max(1,4)} \times 5^{\max(1,0)} = 2^4 \times 5^0 = 80\)。
另外,这个性质也是 \([a_1,a_2](a_1,a_2) = a_1a_2\) 的一种直接证明,以 \(10\) 和 \(16\) 为例:\((10,16)[10,16] = 2^{\min(1,4)} \times 5^{\min(1,0)} \times 2^{\max(1,4)} \times 5^{\max(1,0)} = 2^{\min(1,4) + \max(1,4)} \times 5^{\min(1,0) + \max(1,0)} = 2^{1+4} \times 5^{1+0}\),\(10 \times 16 = 2 \times 5 \times 2^4 = 2^{1+4} \times 5^{1+0}\)。
所以 \([a_1,a_2](a_1,a_2) = a_1a_2\) 的本质其实是 \(\min(\alpha,\beta) + \max(\alpha,\beta) = \alpha + \beta\)。
推论:用除数函数 \(\tau(a)\) 表示 \(a\) 的所有正约数的个数,则 \(\tau(a) = (\alpha_1+1) \cdots (\alpha_s + 1) = \tau(p_1^{\alpha_1}) \cdots \tau(p_s^{\alpha_s})\)。
相当于对于每个质因子上的幂次,可以取 \(0\) 到 \(\alpha_i\) 中的任意整数,共 \(\alpha_i + 1\) 个,由乘法原理可以直接得出,约数的个数。
比如,\(a = 2^7 \times 3^8 \times 5^9\),则 \(a\) 的正约数个数等于 \((7+1)(8+1)(9+1) = 8 \times 9 \times 10 = 720\)。
推论:用除数和函数 \(\sigma(a)\) 表示 \(a\) 的所有正约数的和,则 \(\sigma(a) = \dfrac{p_1^{\alpha_1 + 1} - 1}{p_1 - 1} \cdots \dfrac{p_s^{\alpha_s + 1} - 1}{p_s - 1} = \sigma(p_1^{\alpha_1}) \cdots \sigma(p_s^{\alpha_s})\)。
比如,\(a = 120 = 2^3 \times 3 \times 5\) 的因子分别是 \(1,2,3,4,5,6,8,10,12,15,20,24,30,40,60,120\)。
用等比数列求和公式 \(\dfrac{p_1^{\alpha_1 + 1} - 1}{p_1 - 1} = 1 + p_1 + \cdots + p_1^{\alpha_1}\) 展开计算 \(\sigma(120) = \dfrac{2^4 - 1}{2 - 1} \dfrac{3^2-1}{3-1} \dfrac{5^2-1}{5-1} = (2^3+2^2+2^1+1)(3^1+1)(5^1+1)\),把括号展开,发现 \(\sigma(120) = (2^3+2^2+2^1+1)(3^1+1)(5^1+1) = 120+24+40+8+60+12+20+4+30+6+10+2+15+3+5+1\),等于之前的约数之和。
公式是乘法原理在乘法分配律上的体现,也展现了质因子之间的独立性。
例题:P1069 [NOIP2009 普及组] 细胞分裂
给定 \(m_1 \ (m_1 \le 30000), \ m2 \ (m2_le 10000)\) 和 \(n \ (n \le 10000)\) 个正整数 \(S_i \ (S_i \le 2 \times 10^9)\)。设 \(x_i\) 是最小的使得 \(m_1^{m_2} | S_i^{x_i}\) 的整数(也有可能不存在),求 \(\min(x_1, \cdots, x_n)\)。
分析:\(m_1^{m_2}\) 很大,难以直接处理。考虑 \(m_1 = p_1^{\alpha_1} p_2^{\alpha_2} \cdots p_s^{\alpha_s}\),那么 \(m_1^{m_2} = p_1^{\alpha_1 m_2} p_2^{\alpha_2 m_2} \cdots p_s^{\alpha_s m_2}\)。接下来只需要解决题意中的 \(x_i\) 的求解。
当 \(m_1^{m_2}\) 中的每个质因子的幂次都不超过 \(S_i^{x_i}\) 时,\(m_1^{m_2} | S_i^{x_i}\) 成立。\(S_i^{x_i}\) 中的质因子是否出现由 \(S_i\) 决定,而质因子出现了几次主要由 \(x_i\) 决定。若 \(S_i = p_1^{e_1} p_2^{e_2} \cdots p_s^{e_s} p_{s+1}^{e_{s+1}} \cdots p_{s+r}^{e_{s+r}}\),其中 \(p_{s+1}\) 到 \(p_{s+r}\) 表示与 \(m_1\) 无关的质因子,那么 \(x_i\) 应该使得对于所有 \(1 \le j \le s\),满足 \(\alpha_j m_2 \le e_j x_i\)。
所以从 \(m_1\) 的每个质因子 \(p_j\) 出发:如果这个 \(S_i\) 不能整除 \(p_j\),则说明 \(S_i\) 不包含这个质因子,进而说明找不到题设要求的 \(x_i\);如果这个 \(S_i\) 能整除 \(p_j\),那么只要求出对应的 \(e_j\),就能算出第 \(j\) 个质因子,要求 \(x_i\) 不小于 \(\lceil \dfrac{\alpha_j m_2}{e_j} \rceil\),再对所有这样的要求取最大值,就得到了 \(x_i\)。最后对所有合法的 \(x_i\) 取最小值就是答案。
参考代码
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 200;
int cnt[N], cnts[N];
int main()
{
int n, m1, m2;
scanf("%d%d%d", &n, &m1, &m2);
int m = m1;
// 对m1分解质因数
for (int i = 2; i * i <= m; i++) {
while (m1 % i == 0) {
cnt[i]++;
m1 /= i;
}
}
int ans = -1;
for (int i = 1; i <= n; i++) {
for (int j = 0; j < N; j++) cnts[j] = 0;
int s;
scanf("%d", &s);
// 对s分解质因数
for (int j = 2; j * j <= m; j++) {
while (s % j == 0) {
cnts[j]++;
s /= j;
}
}
bool ok = true;
int tmp = 0;
if (m1 > 1) {
int cntm = 0;
while (s % m1 == 0) {
cntm++; s /= m1;
}
if (cntm == 0) continue;
tmp = (m2 + cntm - 1) / cntm;
}
for (int j = 2; j * j <= m; j++) {
if (cnt[j] != 0 && cnts[j] == 0) {
ok = false; break;
}
if (cnt[j] > 0 && cnts[j] > 0) {
tmp = max(tmp, (cnt[j] * m2 + cnts[j] - 1) / cnts[j]);
}
}
if (ok && (ans == -1 || tmp < ans)) ans = tmp;
}
printf("%d\n", ans);
return 0;
}