| Resources | |||||
|---|---|---|---|---|---|
| AryanshS | 通过大量数学竞赛级别的例题和习题介绍模运算 | ||||
| IUSACO | 内容非常简洁,本模块以此为基础 | ||||
| David Altizio | 包含大量数学竞赛例题 | ||||
| CPH | |||||
| PAPS1 | |||||
| CF | 一些练习题 | ||||
| MONT | |||||
简介
在模运算中,我们并不直接处理整数本身,而是处理它们除以 后的余数, 这一过程称为“对 取模”。例如,当 时,我们不直接使用 ,而使用 。通常,题目会给出一个很大的质数 ;最常见的两个模数是 和 。模运算可以避免数值超出内置数据类型 所能表示的范围,因为我们可以按照下列公式随时取余:
模幂
Focus Problem – try your best to solve this problem before continuing!
资料
| Resources | |||||
|---|---|---|---|---|---|
| cp-algo | |||||
二进制快速幂可以高效计算 。其思想是把指数 按二进制 拆分。例如,。因此,只要我们 知道所有指数为二的幂时的 (即 、、、 、),就能在 时间内计算 。
为了处理模数 ,注意取模与乘法相容。因此可以直接实现上述二进制快速幂, 并在每次乘法后将结果对 取模。
题解——Exponentiation
可以使用 Python 内置的 pow 函数高效计算模幂。
MOD = 10**9 + 7for _ in range(int(input())):first, second = [int(i) for i in input().split()]print(pow(first, second, MOD))
模逆元
模逆元对应于实数运算中的倒数:要在模意义下用 除以 ,可以将 乘以 的模逆元。这里我们只考虑模数 为质数的情况。
例如, 在模 下的逆元为 。这意味着对任意整数 ,都有
例如,。
| Resources | |||||
|---|---|---|---|---|---|
| cp-algo | 介绍了多种求模逆元的方法;这里只讨论其中的第二种 | ||||
使用快速幂
费马小定理 (不要与费马大定理混淆)指出:对于所有不能被 整除的整数 , 都有 。于是 ,因此 就是 在模 意义下的一个逆元。
MOD = 10**9 + 7x = pow(2, MOD - 2, MOD)print(x) # 500000004assert 2 * x % MOD == 1
使用欧几里得除法
我们还可以通过欧几里得除法求模逆元。给定质数模数 ,有:
其中 ,。于是:
下面是上述公式的一份简短递归实现:
def inv(x: int) -> int:return x if x <= 1 else MOD - MOD // x * inv(MOD % x) % MOD
这种方法的优点是,可以在 时间内预处理区间 中所有数的模逆元。
inv[1] = 1 # assume we already defined this arrayfor i in range(2, MOD):inv[i] = MOD - MOD / i * inv[MOD % i] % MOD
由于计算模 的逆元需要 时间,在循环中频繁进行除法 会显著增加程序运行时间。如果同一个(或同一批)数的逆元会被多次使用,最好 提前将其预处理出来。
此外,必须始终确保不会除以 。需要注意的是,一个非零数取模后也可能变成 ,因此除数不是常量时尤其要小心。
还可以使用扩展欧几里得算法。参见进阶章节中的对应模块。
C++
模板
下面这些模板实现了模整数类型:数值达到给定模数后会自动取模。
| Resources | |||||
|---|---|---|---|---|---|
| Benq | |||||
| Benq | 可以在比赛中现场写出的简短版本 | ||||
| AtCoder | 包含一个 | ||||
| AtCoder | |||||
下面是使用 Benq 模板的示例:
#include <bits/stdc++.h>using namespace std;const int MOD = 1e9 + 7;Code Snippet: ModInt (Click to expand)int main() {{int a = 1e8, b = 1e8, c = 1e8;
下面是使用 AtCoder 模板的示例:
#include <bits/stdc++.h>using namespace std;// https://atcoder.github.io/ac-library/production/document_en/modint.html// (included in atcoder grading)#include <atcoder/modint>using mint = atcoder::modint;const int MOD = 1e9 + 7;
Java
Python
练习题
| Status | Source | Problem Name | Difficulty | Tags | ||
|---|---|---|---|---|---|---|
| CSES | Easy | Show TagsModular Arithmetic | ||||
| CF | Easy | Show TagsModular Arithmetic | ||||
| Kilonova | Medium | Show TagsMath, Prime Factorization | ||||
| YS | Medium | Show TagsModular Arithmetic | ||||
| CSES | Medium | Show TagsModular Arithmetic | ||||
| Gold | Hard | Show TagsBinary Search, Modular Arithmetic | ||||