模运算
-
a m o d b = a − ⌊ a / b ⌋ × b a\ mod \ b = a - \lfloor a / b \rfloor \times b a mod b=a−⌊a/b⌋×b
-
n m o d p n \ mod\ p n mod p得到的结果的正负至于被除数 n n n有关
模运算的性质:
( a + b ) m o d m = ( ( a m o d m ) + ( b m o d m ) ) m o d m (a + b)\ mod\ m = ((a\ mod\ m) + (b\ mod\ m))\ mod\ m (a+b) mod m=((a mod m)+(b mod m)) mod m
( a − b ) m o d m = ( ( a m o d m ) − ( b m o d m ) ) m o d m (a - b)\ mod\ m = ((a\ mod\ m) - (b\ mod\ m))\ mod\ m (a−b) mod m=((a mod m)−(b mod m)) mod m = ( ( a m o d m ) − ( b m o d m ) + m ) m o d m ((a\ mod\ m) - (b\ mod\ m) + m)\ mod\ m ((a mod m)−(b mod m)+m) mod m
( a × b ) m o d m = ( ( a m o d m ) × ( b m o d m ) ) m o d m (a \times b)\ mod\ m = ((a\ mod\ m) \times (b\ mod\ m))\ mod\ m (a×b) mod m=((a mod m)×(b mod m)) mod m
但是除法例外,除法的取模需要用到逆元。
计算减法的时候,通常需要加上模数,防止出现负数。
乘法逆元
若 a × x ≡ 1 ( m o d b ) a \times x \equiv 1 \ (mod \ b) a×x≡1 (mod b),且 a a a与 b b b互质,我们定义 x x x为 a a a的逆元,记为 a − 1 a^{-1} a−1, x x x可称为 a a a在模 b b b意义下的倒数
对于 a b m o d p \frac{a}{b} \ mod \ p ba mod p,我们可以求出 b b b在 m o d p mod \ p mod p意义下的逆元,然后乘上 a a a,再 m o d p mod \ p mod p即可
注意对于数 a a a在模 p p p意义下的乘法逆元,我们需要确保 a a a与 p p p互质,此时才有 a a a的乘法逆元 a − 1 a^{-1} a−1,此条件等价于 p p p是质数
费马小定理
a p − 1 ≡ 1 ( m o d p ) a^{p - 1} \equiv 1 \ (mod \ p) ap−1≡1 (mod p),其中 p p p是素数
费马小定理求逆元
a × a p − 2 ≡ 1 ( m o d p ) a \times a^{p - 2} \equiv 1 \ (mod\ p) a×ap−2≡1 (mod p),根据乘法逆元的定义可知,此时 a − 1 = a p − 2 a^{-1} = a^{p - 2} a−1=ap−2
扩展欧几里得求逆元
根据逆元的定义 a x ≡ 1 ( m o d p ) ax \equiv 1 \ (mod \ p) ax≡1 (mod p),我们得到方程: a x − 1 = y p ax - 1 = yp ax−1=yp( a x − 1 ax - 1 ax−1 是 p p p的倍数),则 a x + p y = 1 ax + py = 1 ax+py=1
解方程得 x m o d p x \ mod \ p x mod p得到的就是 a a a的乘法逆元,同时逆元存在的条件是 g c d ( a , p ) = 1 gcd(a, p) = 1 gcd(a,p)=1
求阶乘的乘法逆元
同余
两个整数 a a a和 b b b对用一个正整数 m m m取模后余数相同,则称 a a a和 b b b对模 m m m同余,记作 a ≡ b ( m o d m ) a \equiv b \ (mod\ m) a≡b (mod m),这意味着 m ∣ ( a − b ) m\ | \ (a - b) m ∣ (a−b)
同余的性质:
- 自反性: a ≡ a ( m o d m ) a \equiv a \ (mod\ m) a≡a (mod m)
- 对称性:若 a ≡ b ( m o d m ) a \equiv b \ (mod \ m) a≡b (mod m),则 b ≡ a ( m o d m ) b \equiv a \ (mod \ m) b≡a (mod m)
- 传递性:若 a ≡ b ( m o d m ) , b ≡ c ( m o d m ) a \equiv b \ (mod\ m), b \equiv c \ (mod\ m) a≡b (mod m),b≡c (mod m),则 a ≡ c ( m o d m ) a \equiv c \ (mod\ m) a≡c (mod m)
- 同加性:若 a ≡ b ( m o d m ) a \equiv b \ (mod\ m) a≡b (mod m),则 a ± c ≡ b ± c ( m o d m ) a \pm c \equiv b \pm c \ (mod\ m) a±c≡b±c (mod m)
- 同乘性:若 a ≡ b ( m o d m ) a \equiv b \ (mod\ m) a≡b (mod m),则 a × c ≡ b × c ( m o d m ) a \times c \equiv b \times c \ (mod\ m) a×c≡b×c (mod m),若 a ≡ b ( m o d m ) , c ≡ d ( m o d m ) a \equiv b \ (mod \ m), c \equiv d \ (mod \ m) a≡b (mod m),c≡d (mod m),则 a × c ≡ b × d ( m o d m ) a \times c \equiv b \times d \ (mod\ m) a×c≡b×d (mod m)
- 同幂性:若 a ≡ b ( m o d m ) a \equiv b \ (mod \ m) a≡b (mod m),则 a c ≡ b c ( m o d m ) a^c \equiv b^c \ (mod\ m) ac≡bc (mod m)
- 不满足同除性,但是有,若 c a ≡ c b ( m o d m ) ca \equiv cb \ (mod \ m) ca≡cb (mod m),则 a ≡ b ( m o d m g c d ( m , c ) ) a \equiv b \ (\ mod \ \frac{m}{gcd(m, c)}) a≡b ( mod gcd(m,c)m)
扩展欧几里得定理
对于给定的两个整数 a a a, b b b,必须存在整数 x x x与 y y y,使得 a × x + b × y = g c d ( a , b ) a \times x + b \times y = gcd(a, b) a×x+b×y=gcd(a,b)
裴蜀定理
方程 a × x + b × y = c a \times x + b \times y = c a×x+b×y=c有整数解的充分必要条件是 c c c是 g c d ( a , b ) gcd(a, b) gcd(a,b)的倍数
证明:
-
必要性:令 p = g c d ( a , b ) p = gcd(a, b) p=gcd(a,b),则有 a = p × a ′ a = p \times a' a=p×a′, b = p × b ′ b = p \times b' b=p×b′;则 c = p × ( a ′ x + b ′ y ) c = p \times (a'x + b'y) c=p×(a′x+b′y),即 g c d ( a , b ) gcd(a, b) gcd(a,b)的倍数。
-
充分性:考虑 g c d gcd gcd的欧几里得算法。 a , b a, b a,b通过 b , a % b b, a \% b b,a%b的方式一直辗转下去,最后会出现 p , 0 p, 0 p,0的形式。原因是$0 \leq a % b \leq b - 1 。对于递归出口 。对于递归出口 。对于递归出口p, 0 ,方程 ,方程 ,方程a \times p + 0 \times y = c 是否存在解呢?显然有解,由于充分性,这里 是否存在解呢?显然有解,由于充分性,这里 是否存在解呢?显然有解,由于充分性,这里a 取 取 取\frac{c}{p}$即可。那么辗转相除过程中,下面的成立能否推得上面的成立呢?
-
对于方程 b x 1 + a % b × y 1 = c = a x + b y bx_1 + a \% b \times y_1 = c = ax + by bx1+a%b×y1=c=ax+by
-
左边 = b x 1 + ( a − ⌊ a b ⌋ × b ) × y 1 = a y 1 + b x 1 − ⌊ a b ⌋ × b y 1 = a y 1 + b × ( x 1 − ⌊ a b ⌋ × y 1 ) = 右边 = a x + b y 左边 = bx_1 + (a - \lfloor \frac{a}{b} \rfloor \times b) \times y_1 = ay_1 + bx_1 - \lfloor \frac{a}{b} \rfloor \times by_1 = ay_1 + b \times (x_1 - \lfloor \frac{a}{b} \rfloor \times y_1) = 右边 = ax + by 左边=bx1+(a−⌊ba⌋×b)×y1=ay1+bx1−⌊ba⌋×by1=ay1+b×(x1−⌊ba⌋×y1)=右边=ax+by
所以找到一组特解: x = y 1 x = y_1 x=y1, y = x 1 − ⌊ a b ⌋ × y 1 y = x_1 - \lfloor \frac{a}{b} \rfloor \times y_1 y=x1−⌊ba⌋×y1,就可以通过最下面的特解推得所有的特解。
-
对于特解 ( x 0 , y 0 ) (x_0, y_0) (x0,y0),设下一组解是 ( x 0 + d 1 , y 0 + d 2 ) (x_0 + d_1, y_0 + d_2) (x0+d1,y0+d2)
有 a × ( x 0 + d 1 ) + b × ( y 0 + d 2 ) = c a \times (x_0 + d_1) + b \times (y_0 + d_2) = c a×(x0+d1)+b×(y0+d2)=c,又, a × x 0 + b × y 0 = c a \times x_0 + b \times y_0 = c a×x0+b×y0=c,则 a d 1 + b d 2 = 0 ad_1 + bd_2 = 0 ad1+bd2=0
故, d 1 d 2 = − b a = − b / g c d ( a , b ) a / g c d ( a , b ) \frac{d_1}{d_2} = -\frac{b}{a} = -\frac{b / gcd(a, b)}{a / gcd(a, b)} d2d1=−ab=−a/gcd(a,b)b/gcd(a,b)
则 d 1 = b g c d ( a , b ) d_1 = \frac{b}{gcd(a, b)} d1=gcd(a,b)b, d 2 = − a g c d ( a , b ) d_2 = -\frac{a}{gcd(a, b)} d2=−gcd(a,b)a,故一般解为:
x = x 0 + k × b g c d ( a , b ) x = x_0 + k \times \frac{b}{gcd(a, b)} x=x0+k×gcd(a,b)b, y = y 0 − k × a g c d ( a , b ) ( k ∈ Z ) y = y_0 - k \times \frac{a}{gcd(a, b)} \ (k \in Z) y=y0−k×gcd(a,b)a (k∈Z)
-
若要求 x x x的最小整数解,则可以通过 ( x 0 m o d ( b g c d ( a , b ) ) + b g c d ( a , b ) ) m o d x 0 (x_0 \ mod \ (\frac{b}{gcd(a, b)}) + \frac{b}{gcd(a, b)}) \ mod \ x_0 (x0 mod (gcd(a,b)b)+gcd(a,b)b) mod x0,原因是 x 0 x_0 x0的周期是 b g c d ( a , b ) \frac{b}{gcd(a, b)} gcd(a,b)b,所以可通过取模的方式得到结果
-
扩展欧几里得算法
ex
GCD
最大公约数:欧几里得算法,时间复杂度 O ( l o g a ) O(log\ a) O(log a)
g c d ( a , b ) = g c d ( b , a m o d b ) gcd(a, b) = gcd(b, a\ mod\ b) gcd(a,b)=gcd(b,a mod b)
证明如下:
-
令 p = g c d ( a , b ) p = gcd(a, b) p=gcd(a,b),则有 a = p × a ′ a = p \times a' a=p×a′, b = p × b ′ b = p \times b' b=p×b′, g c d ( a ′ , b ′ ) = 1 gcd(a', b') = 1 gcd(a′,b′)=1
-
a m o d b = a − ⌊ a / b ⌋ × b = p × a ′ − p × b ′ × ⌊ a / b ⌋ a\ mod\ b = a - \lfloor a / b \rfloor \times b = p \times a' - p \times b' \times \lfloor a / b \rfloor a mod b=a−⌊a/b⌋×b=p×a′−p×b′×⌊a/b⌋
-
可以看出,$p \ | \ b $, p ∣ ( a m o d b ) p \ | \ (a \ mod \ b) p ∣ (a mod b)
-
-
那么 p p p是否是最大公约数呢?即我们需要证明 g c d ( b ′ , a ′ − b ′ × ⌊ a / b ⌋ ) = 1 gcd(b', a' - b' \times \lfloor a / b \rfloor) = 1 gcd(b′,a′−b′×⌊a/b⌋)=1
- 令 g c d ( b ′ , a ′ − b ′ × ⌊ a / b ⌋ ) = d gcd(b', a' - b' \times \lfloor a / b \rfloor) = d gcd(b′,a′−b′×⌊a/b⌋)=d,则有 b ′ = d × b ′ ′ b' = d \times b'' b′=d×b′′, a ′ − b ′ × ⌊ a / b ⌋ = d × c a' - b' \times \lfloor a / b \rfloor = d \times c a′−b′×⌊a/b⌋=d×c
- 转换得到 a ′ = d × c + b ′ × ⌊ a / b ⌋ = d × c + d × b ′ ′ × ⌊ a / b ⌋ a' = d \times c + b' \times \lfloor a / b \rfloor = d \times c + d \times b'' \times \lfloor a / b \rfloor a′=d×c+b′×⌊a/b⌋=d×c+d×b′′×⌊a/b⌋
- 可以发现 d ∣ b ′ d\ |\ b' d ∣ b′, d ∣ a ′ d\ | \ a' d ∣ a′,与上述 g c d ( a ′ , b ′ ) = 1 gcd(a', b') = 1 gcd(a′,b′)=1矛盾,则命题得证。
欧拉函数
1... N 1...N 1...N中与 N N N互质的数的个数,被称为欧拉函数,记作 ϕ ( N ) \phi(N) ϕ(N)
在唯一分解定理中, N = p 1 a 1 × p 2 a 2 × . . . × p m a m N = p_1^{a_1} \times p_2^{a_2} \times ...\times p_m^{a_m} N=p1a1×p2a2×...×pmam,则 ϕ ( N ) = N × p 1 − 1 p 1 × p 2 − 1 p 2 × . . . × p m − 1 p m \phi(N) = N \times \frac{p_1 - 1}{p_1} \times \frac{p_2 - 1}{p_2} \times ... \times \frac{p_m - 1}{p_m} ϕ(N)=N×p1p1−1×p2p2−1×...×pmpm−1
质数
分解质因数
给定一个数 x x x,由唯一分解定理可知, x = p 1 a 1 × p 2 a 2 × p 3 a 3 . . . ( p 1 < p 2 < p 3 ) x = p_1^{a_1} \times p_2^{a_2} \times p_3^{a_3}...\ (p_1 < p_2 < p_3) x=p1a1×p2a2×p3a3... (p1<p2<p3),我们从小到大枚举每一个数,最先整除 x x x的除数 n n n一定是素数。同时将这个数中所有 n n n的因子除干净,那么下次 x x x被整除时除数也是素数,从而分解了质因数。
#include <bits/stdc++.h>
using namespace std;int main() {int n;cin >> n;for (int i = 0; i < n; i ++) {int x;cin >> x;map<int, int> cnt;vector<int> res;for (int j = 2; j <= x / j; j ++) {if (x % j != 0) continue;res.push_back(j);while (x % j == 0) {cnt[j] ++;x /= j;}}if (x > 1) {res.push_back(x);cnt[x] ++;}for (auto& u : res) {cout << u << " " << cnt[u] << endl;}cout << endl;}return 0;
}
普通筛法
给定一个整数 x x x,并筛掉所有倍数,如 2 x , 3 x , 4 x . . . 2x, 3x, 4x... 2x,3x,4x...
筛完后, v i s [ i ] = f a l s e vis[i] = false vis[i]=false的为素数
这种方法的时间复杂度是 O ( n l o g n ) O(n\ log\ n) O(n log n)级别
对于每一个外层循环变量 i i i,内层循环枚举所有不超过 n n n的 i i i的倍数,枚举次数是 ⌊ n i ⌋ \lfloor \frac{n}{i} \rfloor ⌊in⌋,又 ⌊ n i ⌋ < n i \lfloor \frac{n}{i} \rfloor < \frac{n}{i} ⌊in⌋<in,有调和级数的渐近公式 ∑ i = 1 n 1 i ≈ l n ( n + 1 ) + 0.577218 \sum^{n}_{i = 1} \frac{1}{i} \approx ln(n + 1) + 0.577218 ∑i=1ni1≈ln(n+1)+0.577218,其中 0.577218 0.577218 0.577218是欧拉常数
所以复杂度是 O ( n l o g n ) O(n\ log\ n) O(n log n)级别
虽然这个筛法的时间复杂度很差,但是调和级数枚举引人深思,这种枚举方式非常巧妙,而且复杂度仅有 O ( l o g n ) O(log\ n) O(log n)级别
埃式筛法
在调和级数枚举的筛法中,我们发现枚举4的倍数无意义,因为从这里筛掉的数一定从2的倍数里筛掉了,所以我们想到:只用质数去筛
其复杂度只有 O ( n l o g l o g n ) O(n\ log\ log\ n) O(n log log n)
#include <bits/stdc++.h>
using namespace std;const int N = 1e6 + 10;
int cnt, primes[N], n;
bool st[N];int main() {cin >> n;for (int i = 2; i <= n; i ++) {if (st[i]) continue;primes[cnt ++] = i;for (int j = 2 * i; j <= n; j += i) {st[j] = true;}}cout << cnt << endl;return 0;
}
欧拉筛
通过对埃氏筛法的分析,我们发现 6 = 2 × 3 6 = 2 \times 3 6=2×3会被质数 2 2 2和 3 3 3各筛一次。一个数有多少个质因子,它就会被筛多少次。那么我们能否让一个数只被筛掉一次呢?
欧拉筛法可以做到并且每个数会被它的最小质因子筛掉
#include <bits/stdc++.h>
using namespace std;const int N = 1e6 + 10;
int cnt, primes[N], n;
bool st[N];int main() {cin >> n;for (int i = 2; i <= n; i ++) {if (!st[i]) primes[cnt ++] = i; //是素数for (int j = 0; j < cnt && primes[j] <= n / i; j ++) {st[primes[j] * i] = true;if (i % primes[j] == 0) break;}}cout << cnt << endl;return 0;
}
- 设 x = i × p r i m e s [ j ] x = i \times primes[j] x=i×primes[j]
- 若 i m o d p r i m e s [ j ] ≠ 0 i \ mod \ primes[j] \neq 0 i mod primes[j]=0,则 i i i中没有 p r i m e s [ j ] primes[j] primes[j]这个质因子。又因为 j j j是从小到大遍历的,所以 p r i m e s [ j ] < i primes[j] < i primes[j]<i,则 p r i m e s [ j ] primes[j] primes[j]是 x x x的最小质因子
- 若 i m o d p r i m e s [ j ] = 0 i \ mod \ primes[j] = 0 i mod primes[j]=0 ,说明 p r i m e s [ j ] primes[j] primes[j]是 i i i的一个质因子。又因为 j j j是从小到大遍历的,所以 p r i m e s [ j ] primes[j] primes[j]是 i i i的最小质因子。所以 p r i m e s [ j ] primes[j] primes[j]是 x x x的最小质因子
- 综上所述,每个数都是被其最小质因子 p r i m e s [ j ] primes[j] primes[j]筛掉且只会被筛掉一次
约数
约数个数
对于一个正整数 x x x,由于唯一分解定理, x = p 1 a 1 × p 2 a 2 × p 3 a 3 × p 4 a 4 . . . x = p_1^{a_1} \times p_2^{a_2} \times p_3^{a_3} \times p_4^{a_4}... x=p1a1×p2a2×p3a3×p4a4...
对于 x x x的每一个约数 y y y, y y y都能写成 y = p 1 b 1 × p 2 b 2 × p 3 b 3 × p 4 b 4 . . . ( 0 ≤ b 1 ≤ a 1 , 0 ≤ b 2 ≤ a 2 , 0 ≤ b 3 ≤ a 3 , 0 ≤ b 4 ≤ a 4 ) y = p_1^{b_1} \times p_2^{b_2} \times p_3^{b_3} \times p_4^{b_4}... \ (0 \leq b_1 \leq a_1,0 \leq b_2 \leq a_2, 0 \leq b_3\leq a_3,0 \leq b_4 \leq a_4) y=p1b1×p2b2×p3b3×p4b4... (0≤b1≤a1,0≤b2≤a2,0≤b3≤a3,0≤b4≤a4)
所以约数个数为$(a_1 + 1) \times (a_2 + 1) \times (a_3 + 1) \times (a_4 + 1) \times … $
约数之和
约数之和 s u m = ( p 1 0 + p 1 1 + . . . + p 1 a 1 ) × ( p 2 0 + p 2 1 + . . . + p 2 a 2 ) × ( p 3 0 + p 3 1 + . . . + p 3 a 3 ) × ( p 4 0 + p 4 1 + . . . + p 4 a 4 ) × . . . sum = (p_1^0 + p_1^1 + ... + p_1^{a_1}) \times (p_2^0 + p_2^1 + ... + p_2^{a_2}) \times (p_3^0 + p_3^1 + ... + p_3 ^ {a_3}) \times (p_4^0 + p_4^1 + ... + p_4^{a_4}) \times ... sum=(p10+p11+...+p1a1)×(p20+p21+...+p2a2)×(p30+p31+...+p3a3)×(p40+p41+...+p4a4)×...
由分配律将上述括号拆开可得: x 1 + x 2 + x 3 + . . . + x_1 + x_2 + x_3 + ... + x1+x2+x3+...+,其中每一项都是 x x x的约数
#include <bits/stdc++.h>
using namespace std;using LL = long long;const int mod = 1e9 + 7;int n;
map<int, int> cnt;int main() {ios::sync_with_stdio(false);cin.tie(nullptr);cin >> n;for (int i = 0; i < n; i ++) {int x;cin >> x;for (int j = 2; j <= x / j; j ++) {if (x % j != 0) continue;int t = 0;while (x % j == 0) {t ++;x /= j;}cnt[j] += t;}if (x > 1) cnt[x] ++;} LL res = 1;for (auto& [u, v] : cnt) {LL t = 0;for (int j = 0; j <= v; j ++) {t = (t * u % mod + 1) % mod;}res = res * t % mod;}cout << res << endl;return 0;
}