Extended Euclidean inverse element Chinese remainder theorem congruence

Posted by XxDeadmanxX on Thu, 20 Jan 2022 09:00:02 +0100

Counting

Template:

long long mul(int a,int b,int mod)
{
    long long ans=1;
    while(b)
    {
        if(b&1) ans=ans*a%mod;
        a=a*a%mod;//Pay attention to the explosion range
        b>>=1;
    }
    return ans;
}

Fast multiplication

Template:

int mul(int a,int b,int mod)
{
    int ans=0;
    while(b)
    {
        if(b&1) ans=(ans+a)%mod;//Pay attention to the explosion range
        a=(a+a)%mod;
        b>>=1;
    }
    return ans;
}

Euclidean algorithm

Euclidean algorithm theorem
Theorem: GCD (a, b) = GCD (B, a, mod, b)
prove:
A can be expressed as a=kb+r, then r=a mod b
1. Suppose d is a common divisor of a and B, then
a|d, b|d, and r=a-kb, so r|d
Therefore, d is the common divisor of (B, a, mod b), and the sufficiency is proved
2. Suppose d is the common divisor of (b,a mod b), then
b|d,r|d, but a=kb +r
Therefore, d is also the common divisor of (a,b), and it is necessary to prove it
Therefore, the common divisor of (a,b) and (b,a mod b) is the same, and its maximum common divisor must be
When b=o, the greatest common divisor of (a, o) is a;
Template:

int gcd(int a,int b)
{
    return b?gcd(b,a%b):a;
}

Extended Euclid

Understanding of the method of solving x, y:
1. Obviously, when b=0, gcd (a, b) =a. At this time, x=1, y=0;
That is, 1a+0b= a;
2. Let ax1+by1=gcd(a,b);
In the next exgcd: bx2+(a mod b)y2=gcd(b,a mod b);
According to Euclidean principle, GCD (a, b) = GCD (B, a, mod, b);
Then: ax1+by1=bx2+(a mod b)y2;
Namely: ax1+by1=bx2+(a-(a/b)b)y2=ay2+bx2-(a/b)by2;
According to the identity theorem:
x1=y2; y1=x2-(a/b)*y2;
In this way, we get the solution of x1 and y1: the values of x1 and y1 are based on X2 and y2.

Template:

int exgcd(int a, int b, int &x, int &y)
{
    if (!b)
    {
        x = 1, y = 0;
        return a;
    }
    int d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

Congruence theorem

a ≡ b ( mod m) <–> m | (a-b);
Linear operation: if a ≡ b(mod m), c ≡ d(mod m), then a ± c ≡ B ± d(mod m), and a * c ≡ b * d(mod m);
Power operation: if a ≡ b (mod m), then a^n ≡ b^n (mod m);

Inverse element

When n is a prime number, the inverse element can be obtained by fast power:
a/b≡ a * x (mod n)
Multiply both sides by B to get a=a* b* x (mod n)
I.e. 1 ≡ b* x (mod n)
Same as b*x ≡ 1 (mod n)
Fermat's small theorem shows that when n is a prime number
b^(n- 1)≡ 1 (mod n)
Remove a B and get b *b^(n-2)= 1 (mod n)
Therefore, when n is a prime number, the multiplicative inverse of b x=b^(n-2);
Template:

#include<iostream>
#include <cmath>
using namespace std;
typedef long long ll;
ll mul(ll a,ll b,ll c)
{
    long long ans=1;
    while(b)
    {
        if(b&1)
        {
            ans=ans*a%c;
        }
        a=a*a%c;
        b>>=1;
    }
    return ans;
}

int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        ll a,b,c;
        cin >> a >> b;
        c=mul(a,b-2,b);
        if(a%b) cout << c << endl;
        else cout << "impossible" << endl;
    }
    return 0;
}

When n is not a prime number, the inverse element can be solved by the extended Euclidean algorithm:
The necessary and sufficient condition for a to have an inverse element is that a and p are coprime, so gcd(a, p) = 1;
Suppose the inverse of a is x, then there is a * x ≡ 1 (mod p)
Equivalent: ax + py = 1
exgcd(a, p, x, y)
Template:

#include <iostream>
using namespace std;
typedef long long LL;
int n;
int exgcd(int a, int b, int &x, int &y)
{
    if (!b) {
        x = 1, y = 0;
        return a;
    }
    int d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

int main()
{
    cin >> n;
    while (n --)
    {
        int a, p, x, y;
        cin >>  a >> p;
        int d = exgcd(a, p, x, y);
        if (d == 1) cout << ((LL)x + p) % p << endl;//Make the result positive
        else puts("impossible");

    }
    return 0;
}

Chinese remainder theorem

x 1≡m1(%a1);
x2 ≡m2(%a2);
x3 ≡m3(%a3);
:
xk ≡mk(%ak);
Look at the first two
k1a1+m1=g2a2+m2; (transfer)
k1a1-g2a2=m2-m1;
First judge whether there is a solution
gcd(a1,a2)|m2-m1;
Extended Euclidean obtains the solution k0 of k1 * a1-g2 * a2=gcd(a1,a2);
k1=(m2-m1)/gcd(a1,a2) * k0;
You can also use gcd (a1,-a2) here, and put the minus sign in g2
The general solution of k1* a1-g2* a2=m2-m1 k=k1 +t* (a2/gcd(a1,a2));
int dd=a2/gcd(a1,a2); (take absolute value)
Here, we should take the minimum positive integer of k1, which can also prevent the explosion range;
k1=(k1%dd+ dd)%dd (because t is arbitrary, it is equivalent to putting it later)
Bring k into the first equation to get x=a1*k1+m1 + t * dd *a1;
New m1=a1 * k1+m1,a1=dd * a1;
At the same time, m1 is the solution obtained by bringing the smallest k1 into the equation, which is the smallest;
Template:

#include <iostream>
using namespace std;
typedef long long LL;
LL x, y;

LL exgcd(LL a, LL b)
{
    if(b == 0)
    {
        x = 1, y = 0;
        return a;
    }
    LL d = exgcd(b, a % b);
    LL z = x;
    x = y;
    y = z - a / b * y;
    return d;
}

int main()
{
    int n;
    cin >> n;
    n--;
    LL a1, a2, m1, m2;
    cin >> a1 >> m1;
    LL d;
    while(n--)
    {
        cin >> a2 >> m2;
        d = exgcd(a1, a2);
        if((m2 - m1) % d)
        {
            cout << "-1" << endl;
            return 0;
        }
        LL k0 = (m2 - m1) / d * x;
        k0 = (k0 % abs(a2 / d) + abs(a2 / d)) % abs(a2 / d);
        m1 = (a1 * k0 + m1);
        a1 = abs(a2 / d * a1);
    }
    cout << m1 << endl;
    return 0;
}

Finally, put a nice picture;

Topics: Algorithm number theory