初等数论中的基础概念

近3年CSPJ考察情况:

题号 题型 分值
2020 第13题 单项选择 2分

难易度:中等

整除

设 有整数 a,b 且 a 不等于 0。

如果存在整数 q,使得 b=aq,那么就说 b 可被 a 整除,记作 a∣b,b 不被 a 整除记作 a∤b。

比如 3∣9的意思是 3 能整除 9 , 而 3∤10 是3不能整除 10。

🌰 给定两个正整数 a,b(0<a,b<10^5) , 判断 a 能否整除 b。

  1. if (b % a == 0) {
  2. printf("a 能整除 b");
  3. } else {
  4. printf("a 不能整除 b");
  5. }

⚡快问快答 题目数量 X 3

DAY2-质数判断和质因数分解 - 图1 DAY2-质数判断和质因数分解 - 图2 DAY2-质数判断和质因数分解 - 图3

取模和取余

C/C++中的运算符 % 其实是取余运算,只是习惯上读作取模。

取余(rem),遵循尽可能让商向0靠近的原则

取模(mod),遵循尽可能让商向负无穷靠近的原则

符号相同时,两者不会冲突。

比如,7 ÷ 3 = 2.3,产生了两个商2和3。

7 =3 * 2 + 1 或 7 = 3 * 3 + (-2)。

因此,7 rem 3 = 1,7 mod 3= 1。

符号不同时,两者会产生冲突。

比如,7 ÷ (-3) = -2.3, 产生了两个商 -2 和 -3。

7=(-3) * (-2) + 1 或 7 = (-3) * (-3) + (-2)。

因此,7 rem (-3) = 1, 7 mod (-3) = (-2).

约数(因数)

约数(因数):若 a∣ba\mid ba∣b,则称 bbb 是 aaa 的倍数,aaa 是 bbb 的约数(因数)。

🌰 给定一个正整数 x(0<x<105)x (0 < x < 10^5)x(0<x<105), 从小到达输出 xxx 的所有约数(因数)。

  1. for (int i = 1; i <= x; i++) {
  2. if ( x % i == 0) {
  3. printf("%d ", i);
  4. }
  5. }

质数与合数

设整数 p>1p > 1p>1。如果 p 除了1和它自身外没有其他约数,那么称 p 为质数(或素数)。

若整数 a≠0,1 且 a 不是质数,则称 a 为合数。

整数的约数(因数)是质数,则该质数称为该整数的质因子。

质数与合数的简单性质:

DAY2-质数判断和质因数分解 - 图4

🌰 给定一个正整数 x(0<x<10^8), 判断其是否为质数。

  1. // 函数返回值 0 为合数,1为质数
  2. bool isPrime(int x) {
  3. for (int i = 2; i * i <= x; i++) {
  4. if ( x % i == 0) {
  5. return 0;
  6. }
  7. }
  8. return 1;
  9. }

Warning!

质数判断中的易错点👇👇👇

互质(互素)

两个整数互素的定义:若 gcd⁡(a1,a2)=1,则称 a1 和 a2 互素。

多个整数互素的定义:若 gcd⁡(a1,…,ak)\=1,则称 a1,…,ak互素。

多个整数互素,不一定两两互素。例如 6、10 和 15 互素,但是任意两个都不互素。

📜历年真题

DAY2-质数判断和质因数分解 - 图5

题解

这是一个简单的容斥原理,首先如果一个数a与10000有大于1的公因数x,那么x必然可以被质因数分解为一些质数的乘积,也就是说只有当a和10000有至少一个相同的质因子的时候,他们之间才会有大于1的公因数。

之后,我们可以对10000分解质因数,分解出来只有2和5。与10000互质的数的个数=数的总数-不与10000互质的数的个数

再考虑1-10000有多少个数里面有2这个质因子,显然有10000/2=5000个(可以举几个例子如1-15,1-20来理解),以此类推,有10000/5=2000个数里面有5这个质因子。

但是答案并不是10000-2000-5000=3000,为什么?因为像10、20这样既有2这个质因子也有5这个质因子的数既被2统计到又被5统计到了。也就是有10这个因子的数被统计到了两次,加上这些数的个数10000/10=1000,就是最后的答案4000 DAY2-质数判断和质因数分解 - 图6 DAY2-质数判断和质因数分解 - 图7

试除法判断质数和分解质因数

近3年CSPJ考察情况:

题号 题型 分值
2020 第19题 完善程序 15分
2022 第19题 完善程序 15分

难易度:中等

2023年备考建议

试除法和质因数分解是一个必须必须要掌握的知识点。因为其算法想法简单,但是考察确很多。究其原因,数论的内容一旦考察深了,就过难,容易没有区分度,比如2021年的筛法考察,那个题目绝大多数考生都是干瞪眼,题是很好,区分度不足。而质因数分解的难度就刚好,而且还可以和其他各种算法做结合。务必会写。

朴素试除法

判断一个数x是否是质数(很多时候称为素性测试),最简单的方法是试除法。试除,就是用2,3,…,x−1这些数字尝试整除x。只要其中有一个数能整除x,就说明x是合数,反之是质数。

  1. // 写成函数形式的试除法,若为合数函数返回0,为质数函数返回1
  2. bool isPrime(int x) {
  3. if (x < 2) return 0;
  4. for (int i = 2; i < x; i++) {
  5. if (x % i == 0) return 0;
  6. }
  7. return 1;
  8. }

试除法(优化后)

程序的过程,就像在数轴x−1的位置建了一堵墙,i从2开始不断右移到这堵“墙”,每次都要进行 x%i的计算,若结果为0,说明i是x的因数,x是合数。

DAY2-质数判断和质因数分解 - 图8

  1. // 优化后的试除法
  2. bool isPrime(long long x) {
  3. if (x < 2) return 0;
  4. // 将 i < x 优化为 i * i <= x
  5. for (long long i = 2; i * i <= x; i++) {
  6. if (x % i == 0) return 0;
  7. }
  8. return 1;
  9. }

DAY2-质数判断和质因数分解 - 图9

分解质因数

给定一个正整数,找到它的所有因数。

DAY2-质数判断和质因数分解 - 图10

  1. vector <int> breakdown(int x) {
  2. vector <int> res;
  3. for (int i = 1; i <= x; i++) {
  4. if (x % i == 0) {
  5. while (x % i == 0) x /= i;
  6. res.push_back(i);
  7. }
  8. }
  9. if (x != 1) res.push_back(x);
  10. return res;
  11. }

历年真题 试除法求质数

(略)