一.费马小定理+快速幂求解+ 欧几里得算法求逆元或扩展欧几里得求逆元
1.费马小定理
若存在整数 a , p 且gcd(a,p)=1,即二者互为质数,则有a^(p-1)≡ 1(mod p)。(这里的 ≡ 指的是左右两边的数对p求模结果相同。a^(p-1)≡ 1(mod p)是指a的p-1次幂取模与1取模恒等)
2.逆元
逆元的用处:
(a + b) % p = (a%p + b%p) %p (对)
(a - b) % p = (a%p - b%p) %p (对)
(a * b) % p = (a%p * b%p) %p (对)
(a / b) % p = (a%p / b%p) %p (错)
eg:(100/50)%20 = 2 ≠ (100%20) / (50%20) %20 = 0
对于一些题目,我们必须在中间过程中进行求余,否则数字太大,电脑存不下,那如果这个算式中出现除法,我们是不是对这个算式就无法计算了呢?
这时就需要逆元了!!! !
定义:
现在有:a*x ≡ 1 (mod p),x叫做a关于p的逆元。
eg:2 * 3 % 5 = 1,那么3就是2关于5的逆元,或者说2和3关于5互为逆元。
a的逆元,我们用inv(a)来表示
那么(a / b) % p = (a * inv(b) ) % p = (a % p * inv(b) % p) % p 这样就把除法,完全转换为乘法。
3.快速幂
求 a^k mod p,时间复杂度 O(logk)
int qmi(int a, int k, int p) // 求a^k mod p
{
int res = 1;
while (k)
{
if (k & 1) res = (LL)res * a % p;
a = (LL)a * a % p;
k >>= 1;
}
return res;
}
4.欧几里得算法
也叫辗转相除法这是小学二年级都会滴
int gcd(int a, int b) // 欧几里得算法
{
return b ? gcd(b, a % b) : a;
}
那我们顺便再说一下
lcm = a/gad(a,b)*b
gcd(ka, kb) = k * gcd(a, b)
lcm(ka, kb) = k * lcm(a, b)
lcm(S/a, S/b) = S/gcd(a, b)
4.求解
a^(p-1) ≡1 (mod p)
两边同除以a
a^(p-2) ≡ inv(a) (mod p)
所以inv(a) = a^(p-2) (mod p) 且 gcd(a,p)==1
综合上述算法就变得非常简单啦
上代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
int gcd(int a, int b) // 欧几里得算法
{
return b ? gcd(b, a % b) : a;
}
int qmi(int a,int k,int p) //快速幂
{
int res = 1;
while(k)
{
if(k&1) res = (LL) res * a % p;
a = (LL)a * a % p;
k >>= 1;
}
return res;
}
int main()
{
int n;
cin >> n;
while(n--)
{
int a,p;
cin >> a >> p;
if(gcd(a,p) != 1) puts("impossible");
else
cout << qmi(a,p-2,p) << endl;
}
return 0;
}
5.扩展欧几里得算法( •̀∀•́ )
裴蜀定理:
定义:对于任意正整数a,b一定存在非零整数x,y使得ax+by = gcd(a, b) 。
当a与b互质时gcd(a,b)==1所以ax+by = 1 两边同时求余b
a*x % b + b*y % b = 1 % b
a*x % b = 1 % b
a*x = 1 (mod b)
所以x是a关于b的逆元
同理:y就是b关于a的逆元
算法代码
#include <iostream>
using namespace std;
typedef long long LL;
void ex_gcd(LL a, LL b, LL &d, LL &x, LL &y)
{
if(!b) x = 1 , y = 0 , d = a;
else
{
ex_gcd(b , a%b , d , y , x);
y -= a/b * x;
}
}
int main()
{
int n;
cin >> n;
while(n --)
{
LL a,b,d,x,y;
cin >> a >> b;
ex_gcd(a,b,d,x,y);
if(d==1) cout << (x + b)%b << endl;
else puts("impossible");
}
return 0;
}
又学会了一个新知识好开心(•̤̀ᵕ•̤́๑)ᵒᵏᵎᵎᵎᵎ
二.中国剩余定理(孙子定理)
中国剩余定理给出了以下的一元线性同余方程组:
中国剩余定理说明:假设整数m1,m2, ... ,mn两两互质,则对任意的整数:a1,a2, ... ,an,
方程组(S)
有解,并且通解可以用如下方式构造得到:
设
是整数m1,m2, ... ,mn的乘积,并设
是除了mi以外的n- 1个整数的乘积。
设
这个就是逆元了
通解形式为
在模M的意义下,方程组(S)只有一个解: