This repository has been archived on 2022-06-22. You can view files and clone it, but cannot push or open issues or pull requests.
usaco-guide/content/6_Advanced/Extend_Euclid.mdx
2020-07-18 19:26:44 -04:00

179 lines
4 KiB
Text

---
id: extend-euclid
title: "Extended Euclidean Algorithm"
author: Benjamin Qi
prerequisites:
- intro-nt
description: "?"
frequency: 1
---
import { Problem } from "../models";
export const metadata = {
problems: {
kat: [
new Problem("Kattis","Modular Arithmetic", "modulararithmetic"),
],
crt: [
new Problem("Kattis","Chinese Remainder", "chineseremainder"),
new Problem("Kattis","Chinese Remainder (non-relatively prime moduli)", "generalchineseremainder"),
],
}
};
## Euclidean Algorithm
<Resources>
<Resource source="cp-algo" url="algebra/euclid-algorithm.html" title="Euclidean"> </Resource>
</Resources>
The original Euclidean Algorithm computes $\gcd(a,b)$ and looks like this:
<LanguageSection>
<CPPSection>
```cpp
ll euclid(ll a, ll b) {
for (;b;swap(a,b)) {
ll k = a/b;
a -= k*b;
}
return a; // gcd(a,b)
}
```
## Extended Euclidean Algorithm
<Resources>
<Resource source="cp-algo" url="algebra/extended-euclid-algorithm.html" title="Extended Euclidean" starred> </Resource>
<Resource source="Wikipedia" url="https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm" title="Extended Euclidean"> </Resource>
<Resource source="cp-algo" url="algebra/linear-diophantine-equation.html" title="Linear Diophantine Equation"> </Resource>
</Resources>
The extended Euclidean algorithm computes integers $x$ and $y$ such that
$$
ax+by=\gcd(a,b)
$$
</CPPSection>
</LanguageSection>
We can slightly modify the version of the Euclidean algorithm given above to return more information!
<LanguageSection>
<CPPSection>
```cpp
array<ll,3> extendEuclid(ll a, ll b) {
array<ll,3> x = {1,0,a}, y = {0,1,b};
// we know that 1*a+0*b=a and 0*a+1*b=b
for (;y[2];swap(x,y)) { // run extended Euclidean algo
ll k = x[2]/y[2];
F0R(i,3) x[i] -= k*y[i];
// keep subtracting multiple of one equation from the other
}
return x; // x[0]*a+x[1]*b=x[2], x[2]=gcd(a,b)
}
int main() {
FOR(a,1,101) FOR(b,1,101) {
auto x = extendEuclid(a,b);
int g = x[2];
assert(g == __gcd(a,b));
if (a != b) assert(abs(x[0]) <= b/g/2 && abs(x[1]) <= a/g/2);
}
}
```
</CPPSection>
</LanguageSection>
### Recursive Version
<LanguageSection>
<CPPSection>
```cpp
ll euclid(ll a, ll b) {
if (!b) return a;
return euclid(b,a%b);
}
```
</CPPSection>
</LanguageSection>
becomes
<LanguageSection>
<CPPSection>
```cpp
pl extendEuclid(ll a, ll b) { // returns {x,y}
if (!b) return {1,0};
pl p = extendEuclid(b,a%b); return {p.s,p.f-a/b*p.s};
}
```
</CPPSection>
</LanguageSection>
The pair will equal to the first two returned elements of the array in the iterative version. Looking at this version, we can prove by induction that when $a$ and $b$ are distinct positive integers, the returned pair $(x,y)$ will satisfy $|x|\le \frac{b}{2\gcd(a,b)}$ and $|y|\le \frac{a}{2\gcd(a,b)}$. Furthermore, there can only exist one pair that satisfies these conditions!
Note that this works when $a,b$ are quite large (say, $\approx 2^{60}$) and we won't wind up with overflow issues.
## Application: Modular Inverse
<Resources>
<Resource source="cp-algo" url="algebra/module-inverse.html" title="Modular Inverse"> </Resource>
</Resources>
<Problems problems={metadata.problems.kat} />
It seems that when multiplication / division is involved in this problem, $n^2 < \texttt{LLONG\_MAX}$.
<LanguageSection>
<CPPSection>
```cpp
ll invGeneral(ll a, ll b) {
array<ll,3> x = extendEuclid(a,b);
assert(x[2] == 1); // gcd must be 1
return x[0]+(x[0]<0)*b;
}
int main() {
FOR(b,1,101) F0R(a,101) if (__gcd(a,b) == 1) {
ll x = invGeneral(a,b);
assert((a*x-1)%b == 0);
assert(0 <= x && x < b);
}
}
```
</CPPSection>
</LanguageSection>
## Application: Chinese Remainder Theorem
<Resources>
<Resource source="cp-algo" url="algebra/linear_congruence_equation.html" title="Linear Congruence Equation"> </Resource>
<Resource source="cp-algo" url="algebra/chinese-remainder-theorem.html" title="Chinese Remainder Theorem"></Resource>
</Resources>
<Problems problems={metadata.problems.crt} />