由于本人是 xxs,数学学的不多,文章有错误还请多多谅解。
质数
质数,也称素数。
若一个数
p p p 为质数,则它的因数只有
1 , p 1, p 1 , p 。
判断质数
判断一个数
p p p 是否是质数,需要判断
2 ∼ p 2\sim \sqrt p 2 ∼ p 是否有数是
p p p 的因数,若有,则说明
p p p 有除了
1 , p 1, p 1 , p 以外的因数,
p p p 不是质数,否则,
p p p 是质数。
时间复杂度
O ( p ) O(\sqrt p) O ( p ) 。
CPP bool is_prime (int p)
{
if (p == 1 ) return false ;
for (int i = 2 ;i * i <= p;i ++)
if (p % i == 0 ) return false ;
return true ;
}
质数筛
埃氏筛
埃氏筛,全称埃拉托斯特尼筛法。
埃氏筛的核心思想是:如果一个数
p p p 是质数,那么
p p p 的倍数的不是质数,即将所有质数的倍数都标记为合数,
不需要标记合数的倍数 。
埃氏筛时间复杂度
O ( n log log n ) O(n \log \log n) O ( n log log n ) ,但是会重复标记(例如
6 6 6 被
2 , 3 2, 3 2 , 3 分别标记了一次),导致常数较大。
CPP bool is_prime[N];
void sieve_primes (int n)
{
for (int i = 1 ;i <= n;i ++) is_prime[i] = true ;
is_prime[1 ] = false ;
for (int i = 2 ;i <= n;i ++)
{
if (is_prime[i] == false ) continue ;
for (int j = i * 2 ;j <= n;j += i)
is_prime[j] = false ;
}
}
欧拉筛
欧拉筛,也称线性筛,是一种比埃氏筛更优秀的筛法。
欧拉筛的核心思想是:对于每个合数,只会被它的最小质因数 给筛掉,从而避免重复标记。
欧拉筛需要多维护一个数组
p r i m e prime p r im e ,
p r i m e i prime_i p r im e i 表示第
i i i 个质数。
欧拉筛需要用当前遍历到的
i i i 和当前筛出的质数
p r i m e j prime_j p r im e j 标记合数,因为
i × p r i m e j i\times prime_j i × p r im e j 一定是合数,先进行标记,然后,最重要的优化来了:如果
i m o d p r i m e j = 0 i\bmod prime_j = 0 i mod p r im e j = 0 ,说明
i i i 的最小质因数为
p r i m e j prime_j p r im e j ,此时应该停止标记。
CPP bool is_prime[N];
int prime[N], tot;
void sieve_primes (int n)
{
for (int i = 1 ;i <= n;i ++) is_prime[i] = true ;
is_prime[1 ] = false ;
for (int i = 2 ;i <= n;i ++)
{
if (is_prime[i] == true ) prime[++ tot] = i;
for (int j = 1 ;j <= tot && prime[j] * i <= n;j ++)
{
is_prime[prime[j] * i] = false ;
if (i % prime[j] == 0 ) break ;
}
}
}
整除与同余
整除
设
a a a 是非零整数,
b b b 是整数。若存在一个整数
x x x ,使得
b = a × x b = a\times x b = a × x ,那么称
b b b 可被
a a a 整除 或
a a a 可以
整除 b b b ,记作
a ∣ b a\mid b a ∣ b ,也可以说
b b b 是
a a a 的倍数或
a a a 是
b b b 的因数。例如
2 ∣ 6 , 4 ∣ 8 2 \mid 6,4\mid 8 2 ∣ 6 , 4 ∣ 8 。
整除具有以下性质:
性质 1 1 1 :如果 a ∣ b a\mid b a ∣ b 并且 b ∣ c b\mid c b ∣ c ,那么 a ∣ c a\mid c a ∣ c
性质 2 2 2 :a ∣ b a\mid b a ∣ b 并且 b ∣ c b\mid c b ∣ c 等价于 a ∣ ( b × x + c × y ) a\mid (b\times x + c\times y) a ∣ ( b × x + c × y )
性质 3 3 3 :设 m ≠ 0 m\ne 0 m = 0 ,那么 a ∣ b a\mid b a ∣ b 等价于 ( m × a ) ∣ ( m × b ) (m\times a)\mid (m\times b) ( m × a ) ∣ ( m × b )
性质 4 4 4 :设整数 x x x 和 y y y 满足 a × x + b × y = 1 a\times x + b\times y = 1 a × x + b × y = 1 ,且 a ∣ n , b ∣ n a\mid n,b\mid n a ∣ n , b ∣ n ,那么 a × b ∣ n a\times b\mid n a × b ∣ n
证明:
根据性质 3 3 3 可得 a × b ∣ b × n a\times b\mid b\times n a × b ∣ b × n 且 a × b ∣ a × n a\times b\mid a\times n a × b ∣ a × n
再根据性质 2 2 2 可得 a × b ∣ a × n × x + b × n × y a\times b\mid a\times n\times x + b\times n\times y a × b ∣ a × n × x + b × n × y
其中 a × n × x + b × n × y = n × ( a × x + b × y ) = n × 1 = n a\times n\times x + b\times n\times y = n\times(a\times x + b\times y) = n\times 1 = n a × n × x + b × n × y = n × ( a × x + b × y ) = n × 1 = n ,所以 a × b ∣ n a\times b\mid n a × b ∣ n
性质 5 5 5 :若 b = q × d + c b = q\times d + c b = q × d + c ,那么 d ∣ b d\mid b d ∣ b 的充要条件是 d ∣ c d\mid c d ∣ c
同余
若
a , b a,b a , b 为两个整数,且他们的差
a − b a - b a − b 能被某个自然数
p p p 整除,则称
a a a 和
b b b 关于模
p p p 同余,记作
a ≡ b ( m o d p ) a\equiv b \pmod p a ≡ b ( mod p ) ,意味着
a − b = p × k a - b = p \times k a − b = p × k (
k k k 为某个整数)。例如
36 ≡ 1 ( m o d 5 ) 36\equiv 1 \pmod 5 36 ≡ 1 ( mod 5 ) ,此时
36 − 1 = 35 = 5 × 7 36 - 1 = 35 = 5\times 7 36 − 1 = 35 = 5 × 7 。
对于整数
a , b , c a,b,c a , b , c 和自然数
n , m n,m n , m ,对模
m m m 同余具有以下性质:
自反性:a ≡ a ( m o d m ) a\equiv a \pmod m a ≡ a ( mod m )
对称性:若 a ≡ b ( m o d m ) a\equiv b \pmod m a ≡ b ( mod m ) ,则 b ≡ a ( m o d m ) b\equiv a \pmod m b ≡ a ( mod m )
传递性:若 a ≡ b ( m o d m ) , b ≡ c ( m o d m ) a\equiv b \pmod m,b\equiv c \pmod m a ≡ b ( mod m ) , b ≡ c ( mod m ) ,则 a ≡ c ( m o d m ) a\equiv c \pmod m a ≡ c ( mod m )
同加性:若 a ≡ b ( m o d m ) a\equiv b \pmod m a ≡ b ( mod m ) ,则 a + n ≡ b + n ( m o d m ) a + n\equiv b + n \pmod m a + n ≡ b + n ( mod m )
同乘性:若 a ≡ b ( m o d m ) a\equiv b \pmod m a ≡ b ( mod m ) ,则 a × n ≡ b × n ( m o d m ) a \times n\equiv b \times n \pmod m a × n ≡ b × n ( mod m ) 。若 a ≡ b ( m o d m ) , c ≡ d ( m o d m ) a\equiv b \pmod m,c\equiv d \pmod m a ≡ b ( mod m ) , c ≡ d ( mod m ) ,则 a × c ≡ b × d ( m o d m ) a\times c\equiv b\times d \pmod m a × c ≡ b × d ( mod m )
同幂性:若 a ≡ b ( m o d m ) a\equiv b \pmod m a ≡ b ( mod m ) ,则 a n ≡ b n ( m o d m ) a^n \equiv b^n \pmod m a n ≡ b n ( mod m )
要注意的是,同余
不满足同除性 ,即不满足
a ÷ n ≡ b ÷ n ( m o d m ) a\div n\equiv b\div n \pmod m a ÷ n ≡ b ÷ n ( mod m ) 。
最大公约数
最大公约数指两个整数
a , b a,b a , b 公有的因数中最大的数,记作
gcd ( a , b ) \gcd(a,b) g cd( a , b ) 。
辗转相除法
辗转相除法用来求两个数的最大公约数,又称欧几里得算法,其核心为:
gcd ( x , y ) = gcd ( y , x m o d y ) \gcd(x,y) = \gcd(y, x\bmod y) g cd( x , y ) = g cd( y , x mod y ) 。
证明:
若 x < y x < y x < y ,则 gcd ( y , x m o d y ) = gcd ( y , x ) = gcd ( x , y ) \gcd(y, x\bmod y) = \gcd(y, x) = \gcd(x,y) g cd( y , x mod y ) = g cd( y , x ) = g cd( x , y ) 。
若 x ≥ y x\ge y x ≥ y ,设 x = q × y + r x = q\times y + r x = q × y + r ,其中 0 ≤ r < y 0\le r < y 0 ≤ r < y ,显然 r = x m o d y r = x\bmod y r = x mod y 。对于 x , y x,y x , y 的任意公约数 d d d ,因为 d ∣ x , d ∣ q × y d\mid x,d\mid q\times y d ∣ x , d ∣ q × y ,所以 d ∣ ( x − q × y ) d\mid (x - q\times y) d ∣ ( x − q × y ) ,即为 d ∣ r d\mid r d ∣ r ,因此 d d d 为 y , r y, r y , r 的公约数。
辗转相除法的流程如下:
若 y = 0 y = 0 y = 0 ,则说明答案为 x x x 。
若 y ≠ 0 y\ne 0 y = 0 ,则根据 gcd ( x , y ) = gcd ( y , x m o d y ) \gcd(x, y) = \gcd(y, x\bmod y) g cd( x , y ) = g cd( y , x mod y ) 往下递归。
时间复杂度
O ( log max ( x , y ) ) O(\log \max(x,y)) O ( log max ( x , y )) 。
CPP int gcd (int x, int y)
{
if (y == 0 ) return x;
return gcd (y, x % y);
}
最小公倍数
最小公倍数指两个整数
a , b a,b a , b 公有的倍数中最小的数,记作
lcm ( a , b ) \text{lcm}(a,b) lcm ( a , b ) 。
定理:
x × y = gcd ( x , y ) × lcm ( x , y ) x\times y = \gcd(x, y) \times \text{lcm}(x, y) x × y = g cd( x , y ) × lcm ( x , y ) 。
根据以上定理,可以得出
lcm ( x , y ) = x × y ÷ gcd ( x , y ) \text{lcm}(x, y) = x\times y\div \gcd(x, y) lcm ( x , y ) = x × y ÷ g cd( x , y ) 。
用辗转相除法求出
gcd ( x , y ) \gcd(x, y) g cd( x , y ) 然后直接计算就行了,时间复杂度与辗转相除法一样。
CPP int gcd (int x, int y)
{
if (y == 0 ) return x;
return gcd (y, x % y);
}
int lcm (int x, int y)
{
return x * y / gcd (x, y);
}
欧拉定理
a φ ( n ) ≡ 1 ( m o d n ) a^{\varphi(n)}\equiv 1\pmod n a φ ( n ) ≡ 1 ( mod n )
其中
φ ( n ) \varphi(n) φ ( n ) 为欧拉函数,表示
1 ∼ n 1\sim n 1 ∼ n 中与
n n n 互质的数的个数。
证明
设
x 1 , x 2 , … , x φ ( n ) x_1,x_2,\dots,x_{\varphi(n)} x 1 , x 2 , … , x φ ( n ) 为
1 ∼ n 1\sim n 1 ∼ n 中与
n n n 互质的数。
这时,我们发现
a × x 1 , a × x 2 , … , a × x φ ( n ) a\times x_1, a\times x_2, \dots, a\times x_{\varphi(n)} a × x 1 , a × x 2 , … , a × x φ ( n ) 具有这个性质:每个数
m o d n \bmod n mod n 两两不同,且余数与
n n n 互质。而且,
x 1 , x 2 , … , x φ ( n ) x_1, x_2, \dots, x_{\varphi(n)} x 1 , x 2 , … , x φ ( n ) 也具有这个性质。
有了这个性质,将
a × x 1 , a × x 2 , … , a × x φ ( n ) a\times x_1, a\times x_2, \dots, a\times x_{\varphi(n)} a × x 1 , a × x 2 , … , a × x φ ( n ) 都
m o d n \bmod n mod n 后一定是
φ ( n ) \varphi(n) φ ( n ) 个不同的与
n n n 互质的数,那么:
x 1 × x 2 × ⋯ × x φ ( n ) ≡ a × x 1 × a × x 2 × ⋯ × a × x φ ( n ) ( m o d n ) 1 ≡ a φ ( n ) ( m o d n ) x_1\times x_2\times \dots\times x_{\varphi(n)}\equiv a\times x_1\times a\times x_2\times \dots\times a\times x_{\varphi(n)}\pmod n\\
1\equiv a^{\varphi(n)}\pmod n x 1 × x 2 × ⋯ × x φ ( n ) ≡ a × x 1 × a × x 2 × ⋯ × a × x φ ( n ) ( mod n ) 1 ≡ a φ ( n ) ( mod n )
费马小定理
若整数
p p p 为
质数 且
p p p 与整数
a a a 互质 ,则满足:
a p − 1 ≡ 1 ( m o d p ) a^{p - 1}\equiv 1\pmod p a p − 1 ≡ 1 ( mod p )
证明
因为
p p p 是质数,那么
φ ( p ) = p − 1 \varphi(p) = p - 1 φ ( p ) = p − 1 ,这时就转化成了欧拉定理的一种情况,由于满足欧拉定理,费马小定理一定成立。
裴蜀定理
对于二元一次不定方程
a × x + b × y = c a\times x + b\times y = c a × x + b × y = c ,有解当且仅当
gcd ( a , b ) ∣ c \gcd(a, b)\mid c g cd( a , b ) ∣ c 。
证明
设
d = gcd ( a , b ) d = \gcd(a, b) d = g cd( a , b ) ,显然
d ∣ a , d ∣ b d\mid a, d\mid b d ∣ a , d ∣ b 。
则
d ∣ a × x , d ∣ b × y d\mid a\times x, d\mid b\times y d ∣ a × x , d ∣ b × y 。
那么,要使方程成立,必须满足
d ∣ c d\mid c d ∣ c 。
扩展欧几里得算法
扩展欧几里得算法是用来求解
a × x + b × y = gcd ( a , b ) a\times x + b\times y = \gcd(a, b) a × x + b × y = g cd( a , b ) 的一种算法。
首先,根据数论中的相关定理,此方程一定有解。
因为
gcd ( a , b ) = gcd ( b , a m o d b ) \gcd(a, b) = \gcd(b, a\bmod b) g cd( a , b ) = g cd( b , a mod b ) ,所以
a × x + b × y = gcd ( a , b ) = gcd ( b , a m o d b ) = x × b + y × ( a m o d b ) = x × b + y × ( a − ⌊ a b ⌋ × b ) = y × a + ( x − ⌊ a b ⌋ × y ) × b a\times x + b\times y = \gcd(a, b) = \gcd(b, a\bmod b) = x \times b + y\times (a\bmod b)= x\times b + y\times (a - \lfloor \frac{a}{b} \rfloor \times b) = y\times a + (x - \lfloor \frac{a}{b} \rfloor \times y)\times b a × x + b × y = g cd( a , b ) = g cd( b , a mod b ) = x × b + y × ( a mod b ) = x × b + y × ( a − ⌊ b a ⌋ × b ) = y × a + ( x − ⌊ b a ⌋ × y ) × b 。
可以根据欧几里得算法递归,当
b = 0 b = 0 b = 0 时,可以得出
x = 1 , y = 0 x = 1, y = 0 x = 1 , y = 0 ,。
扩展欧几里得算法流程如下:
当 b = 0 b = 0 b = 0 时,x = 1 , y = 0 x = 1, y = 0 x = 1 , y = 0 。
b ≠ 0 b\ne 0 b = 0 ,则往下递归计算 gcd ( b , a m o d b ) \gcd(b, a\bmod b) g cd( b , a mod b ) ,得到一组解 x ′ , y ′ x',y' x ′ , y ′ ,根据以上的推论,x = y ′ , y = x ′ − ⌊ a b ⌋ × y ′ x = y',y = x' - \lfloor \frac{a}{b} \rfloor \times y' x = y ′ , y = x ′ − ⌊ b a ⌋ × y ′ 。
扩展欧几里得算法时间复杂度与欧几里得算法一样,为
O ( log max ( a , b ) ) O(\log \max(a, b)) O ( log max ( a , b ))
CPP void exgcd (int a, int b)
{
if (b == 0 )
{
x = 1 , y = 0 ;
return ;
}
exgcd (b, a % b);
int tmp = x;
x = y;
y = tmp - a / b * y;
}
逆元
若
a × x ≡ 1 ( m o d p ) a\times x\equiv 1\pmod p a × x ≡ 1 ( mod p ) ,并且
a , p a, p a , p 互质,则称
a a a 模
p p p 的乘法逆元为
x x x ,记作
a − 1 a^{-1} a − 1 。
费马小定理求逆元
注意,当模数
p p p 是质数且
a ≠ 0 a\ne 0 a = 0 时,才可使用费马小定理求逆元。
根据费马小定理:
a p − 1 ≡ 1 ( m o d p ) a^{p - 1}\equiv 1\pmod p a p − 1 ≡ 1 ( mod p )
因此:
a × a p − 2 ≡ 1 ( m o d p ) a\times a^{p - 2}\equiv 1\pmod p\\ a × a p − 2 ≡ 1 ( mod p )
很明显,此时
a p − 2 a^{p - 2} a p − 2 即为
a − 1 a^{-1} a − 1 。
使用快速幂求出
a p − 2 m o d p a^{p - 2}\bmod p a p − 2 mod p 即可,时间复杂度
O ( log p ) O(\log p) O ( log p ) 。
CPP int qpow (int a, int b, int mod)
{
int ans = 1 ;
while (b)
{
if (b & 1 ) ans = ans * a % mod;
a = a * a % mod;
b >>= 1 ;
}
return ans;
}
int get_inv (int a, int p)
{
return qpow (a, p - 2 , p);
}
扩展欧几里得算法求逆元
a × x ≡ 1 ( m o d p ) a\times x\equiv 1 \pmod p a × x ≡ 1 ( mod p ) 可以转化为求解
a × x + p × y = gcd ( a , p ) = 1 a\times x + p\times y = \gcd(a, p) = 1 a × x + p × y = g cd( a , p ) = 1 (当
gcd ( a , p ) = 1 \gcd(a, p) = 1 g cd( a , p ) = 1 才有解,这也符合逆元的定义)。那么,可以使用扩展欧几里得算法求解。
但是,求解出来的
x x x 可能是负数,需要通过累加
p p p 来处理一下。
CPP void exgcd (int a, int b)
{
if (b == 0 )
{
x = 1 , y = 0 ;
return ;
}
exgcd (b, a % b);
int tmp = x;
x = y;
y = tmp - a / b * y;
}
int get_inv (int a, int p)
{
exgcd (a, p);
return (x % p + p) % p;
}
递推求逆元
设
p = k × i + r , r < i , 1 < i < p p = k\times i + r, r < i, 1 < i < p p = k × i + r , r < i , 1 < i < p ,然后把这个式子放在
m o d p \bmod p mod p 意义下可以得到:
k × i + r ≡ 0 ( m o d p ) k\times i + r \equiv 0\pmod p k × i + r ≡ 0 ( mod p )
将两边同时乘上
i − 1 i^{-1} i − 1 和
r − 1 r^{-1} r − 1 可以得到:
k × r − 1 + i − 1 ≡ 0 ( m o d p ) i − 1 ≡ − k × r − 1 ( m o d p ) i − 1 ≡ − ⌊ p i ⌋ × ( p m o d i ) − 1 ( m o d p ) \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ k\times r^{-1} + i^{-1}\equiv 0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \pmod p\\
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ i^{-1}\equiv -k\times r ^ {-1}\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \pmod p\\
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ i^{-1}\equiv - \lfloor \frac{p}{i} \rfloor \times (p\bmod\ i)^{-1}\pmod p k × r − 1 + i − 1 ≡ 0 ( mod p ) i − 1 ≡ − k × r − 1 ( mod p ) i − 1 ≡ − ⌊ i p ⌋ × ( p mod i ) − 1 ( mod p )
通过这个式子即可从前面的数推出当前数的逆元。
CPP void get_inv (int n, int p)
{
inv[1 ] = 1 ;
for (int i = 2 ;i <= n;i ++) inv[i] = (p - p / i) * inv[p % i] % p;
}
中国剩余定理
中国剩余定理用来求解以下同余方程组:
{ x ≡ a 1 ( m o d b 1 ) x ≡ a 2 ( m o d b 2 ) … x ≡ a n ( m o d b n ) \begin{cases}
x\equiv a_1&\pmod {b_1}\\
x\equiv a_2&\pmod {b_2}\\
\dots\\
x\equiv a_n&\pmod {b_n}
\end{cases} ⎩ ⎨ ⎧ x ≡ a 1 x ≡ a 2 … x ≡ a n ( mod b 1 ) ( mod b 2 ) ( mod b n )
根据余数的可加性,只有求出以下
n n n 个方程组的解,则可以求出原方程的解:
{ x 1 ≡ a 1 ( m o d b 1 ) x 1 ≡ 0 ( m o d b 2 ) … x 1 ≡ 0 ( m o d b n ) { x 2 ≡ 0 ( m o d b 1 ) x 2 ≡ a 2 ( m o d b 2 ) … x 2 ≡ 0 ( m o d b n ) … { x n ≡ 0 ( m o d b 1 ) x n ≡ 0 ( m o d b 2 ) … x n ≡ a n ( m o d b n ) \begin{cases}
x_1\equiv a_1&\pmod {b_1}\\
x_1\equiv 0&\pmod {b_2}\\
\dots\\
x_1\equiv 0&\pmod {b_n}
\end{cases}
\begin{cases}
x_2\equiv 0&\pmod {b_1}\\
x_2\equiv a_2&\pmod {b_2}\\
\dots\\
x_2\equiv 0&\pmod {b_n}
\end{cases}
\dots
\begin{cases}
x_n\equiv 0&\pmod {b_1}\\
x_n\equiv 0&\pmod {b_2}\\
\dots\\
x_n\equiv a_n&\pmod {b_n}
\end{cases} ⎩ ⎨ ⎧ x 1 ≡ a 1 x 1 ≡ 0 … x 1 ≡ 0 ( mod b 1 ) ( mod b 2 ) ( mod b n ) ⎩ ⎨ ⎧ x 2 ≡ 0 x 2 ≡ a 2 … x 2 ≡ 0 ( mod b 1 ) ( mod b 2 ) ( mod b n ) … ⎩ ⎨ ⎧ x n ≡ 0 x n ≡ 0 … x n ≡ a n ( mod b 1 ) ( mod b 2 ) ( mod b n )
原方程解
x = ∑ i = 1 n x i x = \sum^{n}_{i = 1} x_i x = ∑ i = 1 n x i 。
{ x c ≡ 0 ( m o d b 1 ) x c ≡ 0 ( m o d b 2 ) … x c ≡ a c ( m o d b c ) … x c ≡ 0 ( m o d b n ) \begin{cases}
x_c\equiv 0&\pmod {b_1}\\
x_c\equiv 0&\pmod {b_2}\\
\dots\\
x_c\equiv a_c&\pmod {b_c}\\
\dots\\
x_c\equiv 0&\pmod {b_n}
\end{cases} ⎩ ⎨ ⎧ x c ≡ 0 x c ≡ 0 … x c ≡ a c … x c ≡ 0 ( mod b 1 ) ( mod b 2 ) ( mod b c ) ( mod b n )
将上方程组转化为:
{ y c ≡ 0 ( m o d b 1 ) y c ≡ 0 ( m o d b 2 ) … y c ≡ 1 ( m o d b c ) … y c ≡ 0 ( m o d b n ) \begin{cases}
y_c\equiv 0&\pmod {b_1}\\
y_c\equiv 0&\pmod {b_2}\\
\dots\\
y_c\equiv 1&\pmod {b_c}\\
\dots\\
y_c\equiv 0&\pmod {b_n}
\end{cases} ⎩ ⎨ ⎧ y c ≡ 0 y c ≡ 0 … y c ≡ 1 … y c ≡ 0 ( mod b 1 ) ( mod b 2 ) ( mod b c ) ( mod b n )
那么,
x c = y c × a c x_c = y_c\times a_c x c = y c × a c 。
由于
b i b_i b i 两两互质,可得
y c m o d ∏ i = 1 n b i b c = 0 y_c\bmod \frac{\prod_{i = 1}^{n} b_i}{b_c} = 0 y c mod b c ∏ i = 1 n b i = 0 。设
∏ i = 1 n b i b c \frac{\prod_{i = 1}^{n} b_i}{b_c} b c ∏ i = 1 n b i 为
l c l_c l c ,则
b c = l c × w c b_c = l_c\times w_c b c = l c × w c 。
根据以上方程组,可知
l c × w c ≡ 1 ( m o d b c ) l_c\times w_c\equiv 1\pmod {b_c} l c × w c ≡ 1 ( mod b c ) ,显然
w c w_c w c 就是
l c l_c l c 的逆元,直接使用扩展欧几里得算法求就行了。
方程解
x = ∑ i = 1 n a c × l c × l c − 1 x = \sum_{i = 1}^{n} a_c\times l_c\times l_c^{-1} x = ∑ i = 1 n a c × l c × l c − 1 。
由于需要求的是方程的
最小正整数解 ,需要累加
∏ i = 1 n a i \prod_{i = 1}^{n} a_i ∏ i = 1 n a i 并取模。
CPP void exgcd (int a, int b)
{
if (b == 0 )
{
x = 1 , y = 0 ;
return ;
}
exgcd (b, a % b);
int tmp = x;
x = y;
y = tmp - a / b * y;
}
for (int i = 1 ;i <= n;i ++)
{
int qwq = cj / a[i];
exgcd (qwq, a[i]);
ans = (ans + qwq * b[i] * x) % cj;
}
cout << (ans + cj) % cj;
欧拉函数
欧拉函数
φ ( n ) \varphi(n) φ ( n ) 表示
1 ∼ n 1\sim n 1 ∼ n 中与
n n n 互质的数的个数,特别的,
φ ( 1 ) = 1 \varphi(1) = 1 φ ( 1 ) = 1 。
欧拉函数是一个积性函数,若
n ⊥ m n\perp m n ⊥ m ,则
φ ( n × m ) = φ ( n ) × φ ( m ) \varphi(n\times m) = \varphi(n)\times \varphi(m) φ ( n × m ) = φ ( n ) × φ ( m ) 。
设
n n n 分解质因数后为
∏ i = 1 m p i q i \prod_{i = 1}^mp_i^{q_i} ∏ i = 1 m p i q i ,则
φ ( n ) = n × ∏ i = 1 m ( 1 − 1 p i ) \varphi(n) = n\times \prod_{i = 1}^m (1 - \frac{1}{p_i}) φ ( n ) = n × ∏ i = 1 m ( 1 − p i 1 ) 。
证明
由于欧拉函数是一个积性函数,只需要考虑
p i q i p_i^{q_i} p i q i 的取值就能计算所有数的欧拉函数了。
若一个数与
p i q i p_i^{q_i} p i q i 不互质,则这个数一定是
p i p_i p i 的倍数,那么
1 ∼ p i q i 1\sim p_i^{q_i} 1 ∼ p i q i 中有
p i q i − 1 p_i^{q_i - 1} p i q i − 1 个数和
p i q i p_i^{q_i} p i q i 不互质,反过来和
p i q i p_i^{q_i} p i q i 互质的数的个数为
p i q i − p i q i − 1 = p i q i × ( 1 − 1 p i ) p_i^{q_i} - p_i^{q_i - 1} = p_i^{q_i}\times (1 - \frac{1}{p_i}) p i q i − p i q i − 1 = p i q i × ( 1 − p i 1 ) ,则
φ ( n ) = n × ∏ i = 1 m ( 1 − 1 p i ) \varphi(n) = n\times \prod_{i = 1}^m (1 - \frac{1}{p_i}) φ ( n ) = n × ∏ i = 1 m ( 1 − p i 1 ) 。
O ( n ) O(\sqrt n) O ( n ) 求解
φ ( n ) \varphi(n) φ ( n ) :
CPP phi = n;
for (int i = 2 ;i * i <= n;i ++)
if (n % i == 0 )
{
phi = phi / i * (i - 1 );
while (n % i == 0 ) n /= i;
}
if (n != 1 ) phi = phi / n * (n - 1 );
但是,以上算法如果计算多个数的欧拉函数,容易超时,需要使用欧拉筛优化,时间复杂度
O ( n ) O(n) O ( n ) :
CPP phi[i] = 1 ;
for (int i = 2 ;i <= n;i ++)
{
if (phi[i] == 0 )
p[++ tot] = i, phi[i] = i - 1 ;
for (int j = 1 ;j <= tot && i * p[j] <= n;j ++)
{
if (i % p[j] == 0 )
{
phi[i * p[j]] = phi[i] * p[j];
break ;
}
else phi[i * p[j]] = phi[i] * (p[j] - 1 );
}
}