算术基本定理
一个整数可以被表示成若干质数的乘积。例如:
算术基本定理:设
朴素的分解质因数的时间复杂度和枚举约数一样都是
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; }
算术基本定理是处理整除性和数论函数的有力工具。
假定
推论:
每个质因子上的幂次直接决定了两数之间的整除性。
例如
推论:若
比如,
另外,这个性质也是
所以
推论:用除数函数
相当于对于每个质因子上的幂次,可以取
比如,
推论:用除数和函数
比如,
用等比数列求和公式
公式是乘法原理在乘法分配律上的体现,也展现了质因子之间的独立性。
例题:P1069 [NOIP2009 普及组] 细胞分裂
给定
和 个正整数 。设 是最小的使得 整除 的整数(也有可能不存在),求 。
分析:
当
所以从
参考代码
#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; }
习题:P9836 种树
解题思路
假设树高
每次施肥实际上是考虑肥料
分析这个式子可以发现,原来的
时间复杂度为
参考代码
#include <cstdio> const int N = 10005; const int M = 1500; const int MOD = 998244353; int cnt[N][M], prime[N], len; bool is_prime[N]; void init() { for (int i = 2; i < N; i++) is_prime[i] = true; for (int i = 2; i < N; i++) { if (is_prime[i]) { prime[++len] = i; for (int j = i * 2; j < N; j += i) is_prime[j] = false; } } } int main() { init(); int n, w; scanf("%d%d", &n, &w); for (int i = 1; i <= n; i++) { int x; scanf("%d", &x); for (int j = 1; j <= len; j++) { cnt[i][j] = 1; while (x % prime[j] == 0) { cnt[i][j]++; x /= prime[j]; } } } for (int i = 1; i <= len; i++) { while (w % prime[i] == 0) { int minj = 1; for (int j = 2; j <= n; j++) if (cnt[j][i] < cnt[minj][i]) minj = j; cnt[minj][i]++; w /= prime[i]; } } int ans = 1; for (int i = 1; i <= n; i++) for (int j = 1; j <= len; j++) ans = 1ll * ans * cnt[i][j] % MOD; printf("%d\n", ans); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)