同余问题

前言

我发现我的数论知识整理 , 整理的真的很乱,我觉得有必要重新整理梳理一下,就先从同余开始吧,前面的也没有什么可以梳理的,就是比较简单的结论和证明。(但也不代表本章很难,笔者是个 (fw) ,所以整理不出很 (nb) 的东西)

这篇文章能够提供什么学习内容,即这篇文章你能够学到什么 :

  • (1.) 欧拉函数 ( ext{&}) 欧拉定理
  • (2.) 乘法逆元
  • (3.) 扩展欧几里得
  • (4.) 同余方程
  • (5.) 中国剩余定理

一些表示

  • (1.) (equiv) 表示的模意义下相等
  • (2.) (varphi) 表示欧拉函数
  • (3.) (p) 无特殊说明为一个质数。

同余的性质

  • (1.) 自反性:(a equiv a (mod p ))
  • (2.) 对称性:(a equiv b, b equiv a (mod p))
  • (3.) 传递性:(aequiv b ,bequiv c , aequiv c(mod p))
  • (4.) 满足运算律 (a equiv b , c equiv d , aigoplus c equiv bigoplus d(mod p))

(igoplus) 代表运算。

虽然说很显然,但是也是需要放在前面的。

还有就是,对负数取模的时候, (ret = (ret + mod) ext{%} mod) , 当然,不要 (define int unsigned long long) , 该事例来源于机房某憨批。

欧拉函数 & 欧拉定理

首先声明,欧拉函数是没有欧拉定理的。

欧拉函数

(varphi(N)) 为欧拉函数,为 ([1,N]) 中与 (N) 互质的数的个数。
一个小定理 :

  • (N = prod_{ m{p|N}}{p_i}^{c_i})
    (varphi(N) = N imes prod_{p|N}(1 - frac{1}{p}))

证明 : 涉及一个容斥原理。
我们设 (N) 的一个质因子为 (p) , 那么 (p) 的倍数有 (frac{N}{p}) 个,同理,若 (q) 也是 (N) 的一个质因子,那么 (q) 的倍数有 (frac{N}{q}) 个,
我们去掉这些数 (因为不能有互质的,(N) 和他们的最大公约数都不是,是 (p)(q)) .
那么我们就删掉了 (pq) 的倍数两次,给它加回来(容斥) 。
那么最后我们能得到 (N - frac{N}{p} - frac{N}{q} + frac{N}{pq} = N imes (1 - frac{1}{p}) imes (1 - frac{1}{q}))

如果需要计算欧拉函数的话,我们就根据上述,直接搞一个质因数的分解,顺带求出欧拉函数。

欧拉定理

若正整数 (a , n) 互质,则 (a^{varphi(n)} equiv 1(mod p))

证明 : 咕了。

欧拉定理的推论

若正整数 (a,n) 互质,则对于任意的正整数 (b) ,有 (a^b equiv a^{b mod varphi(p)} (mod p))

证明:来源:抄书
(b = q imes varphi(p) + r) , 其中 $ 0 leq r < varphi(p) $ , 即 (r = b mod varphi(p))
(a^b equiv a^{q imes varphi(p) + r}equiv a^{varphi(p)^q} imes a^r equiv 1^q imes a^r equiv a^r equiv a^{b mod varphi(p)} (mod p))
得证。

扩展欧拉定理

[a^b equiv egin{cases} a^b &b leq varphi(p) \ a^{b mod varphi(p) + varphi(p)}, & b > varphi(p) end{cases} ( mod p) ]

证明 : 且咕。

乘法逆元

为什么这里要说一下乘法逆元呢? 首先是这里有时候会

因为在模运算中,是不支持除法的,但是我们可以将 (frac{a}{b}) 转化成 (a imes b^{-1}) 的乘法,那么我们这个时候只需要求解出 (b^{-1}) 就好了,你可能会说,这不就是 (frac{1}{b}) 吗? 的确,但是你要明白的是,模运算不支持除法。所以,我们求解 (b^{-1}) 就不能直接 (frac{1}{b})

  • 事先说明 (b^{-1}) 已经不是 (frac{1}{b}) ,而是代表着 (mod p) 意义下的逆元。

我们继续探寻一下这个逆元的性质 ,也就是 (b imes b^{-1} equiv 1(mod p))

我们探讨一下求解的方法

递推式法

确切地来说,这种方法是最容易理解的一种了。 推点式子嘛。

我们假设 (p = k imes i + r) , 则显然是有

[k imes i + r equiv 0 ( mod p ) ]

[k imes i imes i^{-1} imes r^{-1} + r imes r^{-1} imes i^{-1}equiv 0 (mod p) ]

[k imes r^{-1}+ i^{-1} equiv 0(mod p) ]

[i^{-1} equiv -k imes r^{-1} (mod p) ]

那么显然我们同样是可以知道的, (k = lfloorfrac{p}{i} floor , r = p ext{%} i)

那么我们显然 (r < i) ,那么我们就有递推式

[f_i = -lfloorfrac{p}{i} floor imes f_{p ext{%}i} ]

inv[1] =1 ; 
for(qwq int i = 2 ; i <= n ; i++) 
 inv[i] = (- p / i + p) * f[p % i] ;

费马小定理求解逆元

[a^{-1} = a^{p-1} (mod p) ]

这里必须保证 (p) 为质数。

证明:咕了。

上文还有一个欧拉定理求解的。
下文还有一个扩展欧几里得求解的。

扩展欧几里得

首先你需要明白什么是欧几里得。

裴蜀定理

对于任意的正整数 (a , b) 若存在正整数 (x ,y) 使得式子 (ax + by = m) , 则 (gcd(a ,b)|m)

证明 : 我们不断的递归 (gcd(a , b)) ,显然递归到最后一层 ,就是当 (x = 1 , b = 0) 的时候,有一个特殊解 , 无论 (a) 取什么值,都有 (a imes 1 + 0 imes 0 = gcd(0 , a)) .
然后求解 (gcd) 的过程是递归回溯找到的,那么也就会有 (gcd(b , a ext{%} b) = gcd(a , b)) .现在我们假设存在一组解 (x , y),使得其一定满足于 (b imes x + (a ext{%}b) imes y = gcd(b , a ext{%} b)) , 则又因为 (a ext{%} b = a - lfloorfrac{a}{b} floor imes b) , 带入式子我们就有

[b imes x + (a - lfloorfrac{a}{b} floor imes b) imes y = gcd(a , a ext{%}b) ]

这也就等价于

[bx + (a - lfloorfrac{a}{b} floor imes b) imes y <=> ay - b imes (x - lfloorfrac{a}{b} floor) imes y ]

然后我们就得到了通解,继续向上不断的寻找,递归到顶部,最后一定能实现,这时候我们不仅证出了结论,亦求解了出来。

  • 应用
  • (1.) 判断不定方程 (ax + by = m) 是否有解
  • (2.) 求解出不定方程 (ax + by = m) 的解。

扩展欧几里得求解逆元

[a imes a^{-1} equiv 1(mod p) <=> a imes x + py = 1 ]

扩展欧几里得求解逆元其实就是对应着求解不定方程对应着 (1) 的情况 。 直接求解即可。 这里给出扩展欧几里得求解不定方程的代码 :

void exgcd(int a , int b , int &x , int &y) //这里直接传下去,就不用设置全局变量了
{
	if(!b) return (void) (x = 1 , y = 0) ;//某人竟然以为会CE
	exgcd(b , a % b , x , y) ; 
	int k = x ; x = y ; y = k - y * (a / b) ; 
}

扩展欧几里得求解线性同余方程

我们这货和求解逆元长得很像,其实求解逆元就是这个一个特例。

[ax equiv c (mod p) ]

这个同余方程等价于 (ax + py = c)

然后这货就和不定方程一样了。 直接 (exgcd) 求解即可。

中国剩余定理

又称孙子定理。(什么傻逼名字)

普通中国剩余定理

中国剩余定理也就是让你求解一个线性同余方程组。
即为:

[ egin{cases} x equiv a_1 &( mod p_1 )\ x equiv a_2 & (mod p_2) \ …… \x equiv a_n & (mod p_n) end{cases}]

如果 (p_i) 均互质,那么我们称其为中国剩余定理,当然如果不互质,我们叫他扩展中国剩余定理,最后求解出来的是 (x) 的最小值。

  • 一些变量设置 :
  • (1.) (M = prod_{i = 1}^{n}p_i)
  • (2.) (m_i = frac{M}{p_i})
  • (3.) (inv_i) 表示 (m_i)(mod M) 意义下的逆元。

(x = sum_{i = 1}^{n} m_i imes inv_i imes a_i)

证明证明这东西搞懂搞不懂都行,记住也可以
(emm), 我们直接选择带入反向验证是否是正确的,只要是正确的,那么我最后是 (mod M) 的 ,最小值显然是不必担心的。我们发现 (forall k eq i , a_i imes inv_i imes m_i equiv 0 (mod p_k)) , 带入则显然是成立的。

甚至说,中国剩余定理你都可以不用掌握,直接来到 (excrt) 也是可以的。

void exgcd(int a , int b , int &x , int &y) 
{
	if(!b) return (void) (x = 1 , y = 0) ; 
	exgcd(b , a % b , x , y) ; 
	int k = x ; x = y ; y = k - y * (a / b) ; 
}
void init() 
{
	for(qwq int i = 1 ; i <= n ; i++)
	{
		a[i] = read() , p[i] = read() ; //剩余 a_i 条猪
		M = M * p[i] ; 
	}
	for(qwq int i = 1 ; i <= n ; i++) 
	{
		int mi = M / p[i] ; 
		exgcd(mi , p[i] , x , y) ; 
		s = (s + mi * x * a[i]) % M ; 
	}
}

扩展中国剩余定理

这个时候还是求解线性同余方程组

[ egin{cases} x equiv a_1 &( mod p_1 )\ x equiv a_2 & (mod p_2) \ …… \x equiv a_n & (mod p_n) end{cases}]

但是这时候已经不满足 (p_i) 互质了,我们考虑这个问题就只有一个我们是否可以修复呢?很显然答案是否定的。因为在 (p_i) 不互质的情况下, (inv) 可能不存在导致整个算法是错误的。

既然都是合并同余方程组来解决问题的,我们同样也是来合并一下。根据线性同余方程我们可以知道上面的两个式子等价于

[egin{cases} x - p_1 k_1 = a_1 \ x - p_2 k_2 = a_2end{cases} ]

我们就知道 (a_1 + p_1k_1 = a_2 + p_2k_2) , 然后我们继续随便搞一下 (p1k_1 - p_2 k_2 = a_1 - a_2) , 我们发现这个和上述 (ax + by = c) 有着相同的形式,其中 (a_1 , a_2 ,p_1 ,p_2) 均为已知量,在模 (frac{p_1p_2}{gcd(p_1 , p_2)}) 时成立。

然后我们就有了一个 (x = k_1p_1(mod (frac{p_1p_2}{gcd(p_1 , p_2)})))

inline int poow(int a , int b , int mod) 
{
	int ret = 0 ; 
	while(b) 
	{
		if(b & 1) ret = ( ret + a ) % mod ; 
		a = a + a % mod ;
		b >>= 1 ;  
	}
	return ret ; 
}
inline void exgcd(int a , int b , int &x , int &y) 
{
	if(!b) 
	{
		x = 1 , y = 0 ;
		return ; 	
	}
	exgcd(b , a % b , x , y) ; 
	int k = x ; 
	x = y ;
	y = k - (a / b) * y ; 
}
inline int query() 
{
	int M = a[1] , ans = b[1] , x , y; 
	for(int i = 2 ; i <= n ; i++) 
	{
		int k = M , l = a[i] , c = (b[i] - ans % l + l) % l ; 
		int gcd = Base::Gcd(k , l) , lcm = l / gcd ; 
		exgcd(k , l , x , y) ;
		if(c % gcd != 0 ) return -1 ; 
		x = poow(x , c / gcd , lcm) ; 
		ans += x * M ;
		M *= lcm ; 
		ans = (ans % M + M) % M ;
	} 
	return (ans % M + M) % M ; 
}
原文地址:https://www.cnblogs.com/Zmonarch/p/14702432.html