暑期集训-数论基础

已结束 IOI 开始于: 2026-7-14 8:00 10 小时 主持人: 58

数论基础

位运算

位运算是直接对整数的二进制位进行操作。由于计算机内部使用二进制存储整数,因此位运算通常具有较高的执行效率。

基本运算

设两个二进制数为:

a=11002,b=10102a=1100_2,\qquad b=1010_2

按位与 &

只有对应的两个二进制位都为 11,结果位才为 11。

11002& 10102=100021100_2\& \ 1010_2=1000_2

常用于判断某一位是否为 11。

按位或 |

只要对应的两个二进制位中至少有一个为 11,结果位就为 11。

11002 ∣ 10102=111021100_2\ |\ 1010_2=1110_2

常用于将某一位设置为 11。

按位异或 ^

对应的两个二进制位不同时,结果位为 11;相同时,结果位为 00。

11002 ^ 10102=011021100_2\ \hat{}\ 1010_2=0110_2

异或运算具有以下性质:

a⊕0=aa\oplus 0=a a⊕a=0a\oplus a=0 a⊕b=b⊕aa\oplus b=b\oplus a (a⊕b)⊕c=a⊕(b⊕c)(a\oplus b)\oplus c=a\oplus(b\oplus c)

因此,一个数连续异或两次同一个数后保持不变:

a⊕b⊕b=aa\oplus b\oplus b=a

按位取反 ~

将整数的每一个二进制位取反,即 00 变为 11,11 变为 00。

在补码表示下,有:

∼x=−x−1\sim x=-x-1

左移 <<

将二进制位整体向左移动,右侧补 00。

在不发生溢出的情况下:

x≪k=x×2kx\ll k=x\times 2^k

例如:

3≪2=123\ll 2=12

因为:

00112≪2=110020011_2\ll 2=1100_2

右移 >>

将二进制位整体向右移动。

对于非负整数:

x≫k=⌊x2k⌋x\gg k=\left\lfloor\frac{x}{2^k}\right\rfloor

例如:

13≫2=313\gg 2=3

因为:

11012≫2=001121101_2\gg 2=0011_2

常用操作

以下操作中的第 kk 位从第 00 位开始编号。

判断第 kk 位是否为 11

if (x & (1LL << k)) {
    // x 的第 k 位为 1
}

也可以写成:

int bit = (x >> k) & 1;

将第 kk 位设置为 11

x |= 1LL << k;

将第 kk 位设置为 00

x &= ~(1LL << k);

将第 kk 位取反

x ^= 1LL << k;

获取最低位的 11

lowbit(x) 表示 xx 的二进制表示中最低位的 11 所对应的数值。

int lowbit(int x) {
    return x & -x;
}

例如:

12=1100212=1100_2

最低位的 11 对应的数为:

01002=40100_2=4

因此:

lowbit⁡(12)=4\operatorname{lowbit}(12)=4

删除最低位的 11

x &= x - 1;

例如:

12=1100212=1100_2

执行一次后:

11002& 10112=100021100_2\&\ 1011_2=1000_2

每执行一次 x &= x - 1,就会删除一个二进制位中的 11。

因此可以统计一个整数二进制表示中 11 的个数:

int countOne(int x) {
    int cnt = 0;
    while (x) {
        x &= x - 1;
        ++cnt;
    }
    return cnt;
}

时间复杂度为:

O(k)O(k)

其中 kk 为 xx 的二进制表示中 11 的个数。

判断一个正整数是否为 22 的幂

若正整数 xx 是 22 的幂,则它的二进制表示中只有一个 11。

因此:

bool isP(int x) {
    return x > 0 && (x & (x - 1)) == 0;
}

A 找筷子

B 高低位交换

快速幂

任意非负整数 bb 都可以表示成若干个 22 的幂之和。

例如:

13=8+4+1=23+22+2013=8+4+1=2^3+2^2+2^0
long long Pow(long long a, long long b) {
    long long res = 1;

    while (b) {
        if (b & 1)
            res *= a;
        a *= a;
        b >>= 1;
    }

    return res;
}

C 快速幂

素数

  • 整数集合:Z={…,−2,−1,0,1,2,…} \mathbb{Z}=\{\ldots,-2,-1,0,1,2,\ldots\}

  • 自然数集合:N={0,1,2,…}\mathbb{N}=\{0,1,2,\ldots\}

  • 整除:若 a=bka=bk,其中 a,b,ka,b,k 都是整数,则 bb 整除 aa,记作 b∣ab\mid a,否则记作 b∤ab\nmid a。

  • 约数:如 b∣ab\mid a 且 b≥0b\ge 0,则称 bb 是 aa 的约数(因数),aa 是 bb 的倍数。

  • 11 整除任何数,任何数都整除 00。

  • 若 a∣b, a∣ca\mid b,\ a\mid c,则 a∣(b+c), a∣(b−c)a\mid(b+c),\ a\mid(b-c)。

  • 若 a∣ba\mid b,则对任意整数 cc,a∣(bc)a\mid(bc)。

  • 传递性:若 a∣b, b∣ca\mid b,\ b\mid c,则 a∣ca\mid c。

  • 因子:正整数 aa 的平凡约数为 11 和 aa 本身,aa 的非平凡约数称为 aa 的因子。如 2020 的因子有 2、4、5、102、4、5、10。

  • 素数:a>1a>1 且只能被平凡约数整除的数。

  • 合数:a>1a>1 且不是素数的数称为合数。

  • 其他整数(0,10,1,负整数)既不是素数也不是合数。

  • 素数有无穷多个,但分布比较稀疏,不大于 nn 的素数约有 nln⁡n\dfrac{n}{\ln n} 个。

若 nn 是一个合数,则 nn 至少有 11 个素因子。因此其中最小的素因子一定不大于 n\sqrt{n}。

如果 nn 是合数,则一定可以分解为 a×ba\times b 的形式,其中 a≤b, a≠1, b≠na\le b,\ a\ne 1,\ b\ne n,如:

18=2×9,18=3×618=2\times 9,\qquad 18=3\times 6

因 a×a≤a×b=na\times a\le a\times b=n,则可得:

a≤na\le\sqrt{n}

可得判断依据:如果 2∼n2\sim\sqrt{n} 中有 nn 的约数,则 nn 是合数,否则 nn 是素数。

bool isPrime(int n) {
    if (n == 1) return false;
    else {
        for (int i = 2; i * i <= n; i++)
            if (n % i == 0) return false;
        return true;
    }
}

素因数分解

D 因数分解

素数筛

埃氏筛

每个合数 aa 一定可以写成 p×xp\times x 的形式,其中 pp 是素数,xx 是倍数(x≠1x\ne 1)。对于每一个 1∼n1\sim n 内的素数 pp,枚举倍数 xx,把 p×xp\times x 标记为合数,这就是埃氏筛法。

筛选时做一个改进:对于素数 pp,只筛倍数 x≥px\ge p 的数,因为如果 x<px<p,则 xx 中一定有比 pp 小的素因子,p×xp\times x 会在前面的筛选过程中被筛出。

因此只需考虑 2∼n2\sim\sqrt{n} 范围的素数。

时间复杂度:

$$O\left(\frac{n}{2}+\frac{n}{3}+\frac{n}{5}+\cdots\right) =O(n\log\log n)$$
#define maxn 1000000

bool isPrime[maxn + 1]; /* isPrime[i] 为 true 表示 i 为素数 */

void eratos(int n) {
    int i, j;
    isPrime[0] = isPrime[1] = false;

    for (i = 2; i <= n; ++i)
        isPrime[i] = true;

    for (i = 2; i * i <= n; ++i)
        if (isPrime[i]) {
            for (j = i * i; j <= n; j += i)
                isPrime[j] = false;
        }
}

由于数据范围很大,无法生成 [1,R][1,R] 中的所有素数。

使用筛法求出 [2,R][2,\sqrt{R}] 之间的所有素数,对于每个素数 pp,把 [L,R][L,R] 中能被 pp 整除的数标记,即标记:

$$i\times p \qquad \left(\left\lceil\frac{L}{p}\right\rceil \le i\le \left\lfloor\frac{R}{p}\right\rfloor\right)$$

为合数。

将筛出的素数进行相邻两两比较,找出差最大的即可。

欧拉筛法(线性筛)

埃氏筛法中,以 n=50n=50 为例,3030 这个数被筛了 33 次,分别是:

2×15(p=2)2\times 15\quad(p=2) 3×10(p=3)3\times 10\quad(p=3) 5×10(p=5)5\times 10\quad(p=5)

如何用 O(n)O(n) 求 1∼n1\sim n 的素数?

如果每个合数只被它的最小素因数筛除,那么每个数最多只被筛一次。

i=i= 素数表 筛除的数 i=i= 素数表 筛除的数
2 {2}\{2\} {4}\{4\} 13 {2,3,5,7,11,13}\{2,3,5,7,11,13\} {26,39}\{26,39\}
3 {2,3}\{2,3\} {6,9}\{6,9\} 14 {28}\{28\}
4 {8}\{8\} 15 {30,45}\{30,45\}
5 {2,3,5}\{2,3,5\} {10,15,25}\{10,15,25\} 16 {32}\{32\}
6 {12}\{12\} 17 {2,3,5,7,11,13,17}\{2,3,5,7,11,13,17\} {34}\{34\}
7 {2,3,5,7}\{2,3,5,7\} {14,21,35,49}\{14,21,35,49\} 18 {36}\{36\}
8 {16}\{16\} 19 {2,3,5,7,11,13,17,19}\{2,3,5,7,11,13,17,19\} {38}\{38\}
9 {18,27}\{18,27\} 20 {20}\{20\}
10 {20}\{20\} 21 {42}\{42\}
11 {2,3,5,7,11}\{2,3,5,7,11\} {22,33}\{22,33\} 22 {44}\{44\}
12 {24}\{24\} ... ...

枚举 2∼n2\sim n 中的每一个数 ii:

  • 如果 ii 是素数,则保存到素数表中;
  • 利用 ii 和素数表中的素数 prime⁡[j]\operatorname{prime}[j] 去筛除 i×prime⁡[j]i\times\operatorname{prime}[j]。为了确保 i×prime⁡[j]i\times\operatorname{prime}[j] 只被素数 prime⁡[j]\operatorname{prime}[j] 筛除过这一次,要确保 prime⁡[j]\operatorname{prime}[j] 是 i×prime⁡[j]i\times\operatorname{prime}[j] 中最小的素因子,即 ii 中不能有比 prime⁡[j]\operatorname{prime}[j] 还要小的素因子。

E 线性筛素数

约数

若整数 N≥2N\ge 2,那么:

$$N=p_1^{r_1}p_2^{r_2}\cdots p_k^{r_k} \qquad (p_i\text{ 为素数},\ r_i\ge 0)$$

NN 的正约数集合为:

$$\left\{ p_1^{b_1}p_2^{b_2}\cdots p_k^{b_k} \right\} \qquad (0\le b_i\le r_i)$$

NN 的正约数个数为:

$$(r_1+1)(r_2+1)\cdots(r_k+1)=\prod_{i=1}^{k}(r_i+1)$$

除了完全平方数,约数总是成对出现的,即 d≤Nd\le\sqrt{N} 和 Nd≤N\dfrac{N}{d}\le\sqrt{N} 都是 NN 的约数。

NN 的约数个数上界为 2N2\sqrt{N},时间复杂度为 O(N)O(\sqrt{N})。

NN 的所有正约数的和为:

$$(1+p_1+p_1^2+\cdots+p_1^{r_1}) \cdots (1+p_k+p_k^2+\cdots+p_k^{r_k}) = \prod_{i=1}^{k} \left( \sum_{j=0}^{r_i}p_i^j \right)$$

F 反素数

对于任何正整数 xx,其约数的个数计作 g(x)g(x)。例如:

g(1)=1,g(6)=4g(1)=1,\qquad g(6)=4

如果某个正整数 xx 满足:对于任意的 0<i<x0<i<x,都有 g(x)>g(i)g(x)>g(i),那么称 xx 为反素数。例如 1,2,4,61,2,4,6 都是反素数。

现在给定一个数 NN(1≤N≤2×1091\le N\le 2\times 10^9),求出不超过 NN 的最大的反素数。

最大公约数

设 a,ba,b 是不都为 00 的整数,cc 为满足 c∣ac\mid a 且 c∣bc\mid b 的最大整数,则称 cc 是 a,ba,b 的最大公约数,记为 gcd⁡(a,b)\gcd(a,b) 或 (a,b)(a,b)。

最大公约数有如下性质:

gcd⁡(a,b)=gcd⁡(b,a)\gcd(a,b)=\gcd(b,a) gcd⁡(a,b)=gcd⁡(−a,b)\gcd(a,b)=\gcd(-a,b) gcd⁡(a,b)=gcd⁡(∣a∣,∣b∣)\gcd(a,b)=\gcd(|a|,|b|)

若 d∣ad\mid a 且 d∣bd\mid b,则:

d∣gcd⁡(a,b)d\mid\gcd(a,b) gcd⁡(a,0)=a\gcd(a,0)=a gcd⁡(a,ka)=a\gcd(a,ka)=a gcd⁡(an,bn)=ngcd⁡(a,b)\gcd(an,bn)=n\gcd(a,b) gcd⁡(a,b)=gcd⁡(a,ka+b)\gcd(a,b)=\gcd(a,ka+b)

计算 gcd⁡(a,b)\gcd(a,b):枚举法

从 min⁡(a,b)\min(a,b) 到 11 枚举 xx,并判断 xx 是否能同时整除 aa 和 bb。

如果可以,则输出 xx 并退出循环。

时间复杂度为:

O(min⁡(a,b))O(\min(a,b))

计算 gcd⁡(a,b)\gcd(a,b):欧几里得算法

两个整数 a,ba,b(a≥ba\ge b)的公约数集合与 a−ba-b 和 bb 的公约数集合相同,可得:

gcd⁡(a,b)=gcd⁡(b,a mod b)\gcd(a,b)=\gcd(b,a\bmod b)

又称“辗转相除法”。

int gcd(int a, int b) {
    if (b == 0) return a;
    else return gcd(b, a % b);
}

根据 (a,b)⇒(b,a mod b)(a,b)\Rightarrow(b,a\bmod b),设 a>ba>b:

  1. 当 a≥2ba\ge 2b 时,b≤a2b\le\dfrac{a}{2},bb 的规模至少缩小一半;
  2. 当 a<2ba<2b 时,a mod b<a2a\bmod b<\dfrac{a}{2},余数的规模至少缩小一半。

所以时间复杂度为:

O(log⁡(a+b))O(\log(a+b))

G 兔八哥与猎人

H 又是毕业季I

最小公倍数

两个数 a1,a2a_1,a_2 的最小公倍数:

$$\operatorname{lcm}(a_1,a_2) = \frac{a_1a_2}{\gcd(a_1,a_2)}$$$$\operatorname{lcm}(a_1,a_2,a_3) = \operatorname{lcm}(\operatorname{lcm}(a_1,a_2),a_3)$$

以此类推,可以先求 a1,a2a_1,a_2 的最小公倍数 b1b_1,再求 b1b_1 与 a3a_3 的最小公倍数 b2b_2,再求 b2b_2 与 a4a_4 的最小公倍数 b3…b_3\ldots

容斥

现在有:

S={1,2,3,…,600}S=\{1,2,3,\ldots,600\}

求其中可被 2,3,52,3,5 整除的数的数目。

令 A,B,CA,B,C 分别表示 SS 中被 2,3,52,3,5 整除的数的集合。可得:

$$|A|=\left\lfloor\frac{600}{2}\right\rfloor=300,\qquad |B|=\left\lfloor\frac{600}{3}\right\rfloor=200,\qquad |C|=\left\lfloor\frac{600}{5}\right\rfloor=120$$

显然 A,BA,B 集合中一定有相同的元素,比如 6,12,…6,12,\ldots,可继续求 A,B,CA,B,C 两两交集的情况:

$$|A\cap B| = \left\lfloor\frac{600}{2\times 3}\right\rfloor =100$$$$|A\cap C| = \left\lfloor\frac{600}{2\times 5}\right\rfloor =60$$$$|B\cap C| = \left\lfloor\frac{600}{3\times 5}\right\rfloor =40$$

最后求 A,B,CA,B,C 三个集合的交集情况:

$$|A\cap B\cap C| = \left\lfloor\frac{600}{2\times 3\times 5}\right\rfloor =20$$

1783940101098

具有性质 AA 或者 BB 的元素个数,等于具有性质 AA 的元素个数与具有性质 BB 的元素个数的和,减去同时具有性质 AA 和 BB 的元素的个数,使得计算的结果既无遗漏又无重复。这就是容斥原理,一般表示如下:

$$\left|\bigcup_{i=1}^{m}A_i\right| = \sum_{1\le i\le m}|A_i| - \sum_{1\le i<j\le m}|A_i\cap A_j| + \sum_{1\le i<j<k\le m}|A_i\cap A_j\cap A_k| -\cdots + (-1)^{m+1}|A_1\cap A_2\cap\cdots\cap A_m|$$

J 信封问题

取模

如果 a≡b(modm)a\equiv b\pmod m 且有 c≡d(modm)c\equiv d\pmod m,那么下面的模运算律成立:

a+c≡b+d(modm)a+c\equiv b+d\pmod m a−c≡b−d(modm)a-c\equiv b-d\pmod m a×c≡b×d(modm)a\times c\equiv b\times d\pmod m

以下用“% m\%\,m”代表“(modm)\pmod m”:

(a+b)%m=((a%m)+(b%m))%m(a+b)\%m=((a\%m)+(b\%m))\%m (a−b)%m=((a%m)−(b%m)+m)%m(a-b)\%m=((a\%m)-(b\%m)+m)\%m (a×b)%m=((a%m)×(b%m))%m(a\times b)\%m=((a\%m)\times(b\%m))\%m

逆元

对于一个模数 pp 和一个除数 xx,往往能找到一个特殊的数。乘上这个特殊的数,就可以起到除法的效果。这个特殊的数,称为“逆元”。

44 是 33 在模 1111 意义下的逆元。

费马小定理

若 pp 为素数,且 aa 和 pp 互素,则可以得到:

ap−1≡1(modp)a^{p-1}\equiv 1\pmod p

证明:

p−1p-1 个整数 a,2a,3a,…,(p−1)aa,2a,3a,\ldots,(p-1)a 中没有一个是 pp 的倍数,而且没有任意两个模 pp 同余。

所以这 p−1p-1 个数对模 pp 的同余是 1,2,3,…,(p−1)1,2,3,\ldots,(p-1) 的排列。

可得:

$$a\cdot 2a\cdot 3a\cdots(p-1)a \equiv 1\cdot 2\cdot 3\cdots(p-1) \pmod p$$

可化简为:

ap−1(p−1)!≡(p−1)!(modp)a^{p-1}(p-1)!\equiv(p-1)!\pmod p

即:

ap−1≡1(modp)a^{p-1}\equiv 1\pmod p

得证。

一般情况下,在 pp 是素数的情况下,对任意整数 aa 都有:

ap≡a(modp)a^p\equiv a\pmod p

费马小定理应用:pp 是素数,a,pa,p 互素,则:

ab mod p=a b mod (p−1) mod pa^b\bmod p = a^{\,b\bmod(p-1)}\bmod p

如 p=5, a=3p=5,\ a=3:

34=81≡1(mod5)3^4=81\equiv 1\pmod 5

又如:

$$3^{2046} = 3^{4\times 511+2} \equiv 3^2 \pmod 5 \equiv 4 \pmod 5$$

K 【模板】模意义下的乘法逆元

练习

CF58B Coins

CF679A Bear and Prime 100

[POJ 2689] Prime Distance

状态
已结束
规则
IOI
题目
11
开始于
2026-7-14 8:00
结束于
2026-7-14 18:00
持续时间
10 小时
主持人
参赛人数
58