定理3.1.1设m是一个正整数,a是满足m不能整除a的整数,则一次同余式有解的充分必要条件是(a,m)=1,而且,当同余式有解时,其解是唯一的。
1)扩展欧几里得算法:
整数a,b互素的充分必要条件是存在整数s和t,使得sa+tb=1.
对于不完全为 0 的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约数(最大公因数),必然存在整数对 x,y ,使得 gcd(a,b)=ax+by。同余方程ax≡b (mod n),如果 gcd(a,n)== 1,则方程只有唯一解。
在这种情况下,如果 b== 1,同余方程就是 ax=1 (mod n ),gcd(a,n)= 1。 这时称求出的 x 为 a 的对模 n 乘法的逆元。
对于同余方程 ax= 1(mod n ), gcd(a,n)= 1 的求解就是求解方程 ax+ ny= 1,x, y 为整数。这个可用扩展欧几里德算法求出,原同余方程的唯一解就是用扩展欧几里德算法得出的 x 。
-
- 费马小定理求逆元:
设p是一个素数,则对任意整数a,有a^p 同余 a(mod) p。
故a^(p-1) 同余 1(mod) p
故a的逆元为a^(p-2) mod p
- 根据欧拉定理求逆元:
设m是大于1的整数,如果a是满足(a,m)=1的整数,则a^ф(m) 同余 1(mod) m
那么a的逆元为a^(ф(m)-1) (mod) m
2、求欧拉函数值:
φ函数的值 通式:φ(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…..(1-1/pn),其中p1, p2……pn为x的所有质因数,x是不为0的整数。φ(1)=1(唯一和1互质的数(小于等于1)就是1本身)。 (注意:每种质因数只一个。
1)使用广义欧几里得定理求解逆元
- #include <iostream>
- #include <stdio.h>
- using namespace std;
- typedef long long ll;
- void ex_gcd(ll a, ll b, ll &x, ll &y, ll &d)
- {
- if(!b)
- {
- d = a, x=1, y=0;
- }
- else{
- ex_gcd(b, a%b, y, x, d);
- cout << "a=" << a << " " << "b=" << b << " " << "a/b=" << a/b << " " << "a%b=" << a%b << " " << "y="<< y << " " << "x=" << x << " "<< "d= " << d << "\n";
- cout << "************************\n";
- y -= x*(a/b);
- cout << "y=" << y << "\n";
- }
- }
- ll inv(ll t, ll p)
- {
- ll d, x, y;//xt+yp=d gcd(t,p)=d
- ex_gcd(t, p, x, y, d);
- return d == 1?(x%p + p)%p : -1;
- }
- int main()
- {
- ll a, p;
- while(~scanf("%lld %lld", &a, &p))//可输入多组测试样例
- {
- printf("%lld\n", inv(a, p));//如果不存在逆元,输出为-1
- }
- return 0;
- }
- 使用费马小定理求解逆元
- #include <iostream>
- #include <stdio.h>
- using namespace std;
- typedef long long ll;
- ll pow_mod(ll a, ll b, ll p)//快速幂求a^bmod p
- {
- ll ret = 1;
- while(b)
- {
- if(b&1)
- ret = (ret*a)%p;
- a = (a*a)%p;
- b >>= 1;
- }
- return ret;
- }
- ll Fermat(ll a, ll p)
- {
- return pow_mod(a, p-2, p);
- }
- int main()
- {
- ll a, p;
- while(~scanf("%lld %lld", &a, &p))//可输入多组测试样例
- {
- printf("%lld\n", Fermat(a, p));//如果不存在逆元,输出为-1
- }
- return 0;
- }
- // 1000 53 15
- 使用欧拉定理求解逆元
- #include <iostream>
- #include <stdio.h>
- using namespace std;
- typedef long long ll;
- ll phi(ll n) {
- ll ans = n;
- for(int i = 2 ; i*i <= n ; i ++) {
- if(n%i==0) ans = ans - ans/i;
- while(n%i==0) n/=i;
- }
- if(n > 1) ans = ans - ans/n;
- return ans;
- }
- ll pow_mod(ll a, ll b, ll p)//快速幂求a^bmod p
- {
- ll ret = 1;
- while(b)
- {
- if(b&1)
- ret = (ret*a)%p;
- a = (a*a)%p;
- b >>= 1;
- }
- return ret;
- }
- ll oula(ll a, ll p)
- {
- int temp = phi(p);
- return pow_mod(a, temp-1, p);
- }
- int main()
- {
- ll a, p;
- while(~scanf("%lld %lld", &a, &p))//可输入多组测试样例
- {
- printf("%lld\n", oula(a, p));//如果不存在逆元,输出为-1
- }
- return 0;
- }
- // 1000 53 15
2、求欧拉函数值
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- using namespace std;
- int phi(int n) {
- int ans = n;
- for(int i = 2 ; i*i <= n ; i ++) {
- if(n%i==0) ans = ans - ans/i;
- while(n%i==0) n/=i;
- }
- if(n > 1) ans = ans - ans/n;
- return ans;
- }
- int main() {
- int n;
- while(~scanf("%d",&n) && n) {
- printf("%d\n",phi(n));
- }
- }