Chương 4·Bài 47

Extended Euclidean Algorithm

Thuật toán Euclid (bài 08) tìm g=gcd⁡(a,b)g = \gcd(a, b) bằng cách thay (a,b)(a, b) bởi (b,a mod b)(b, a \bmod b). Đi ngược các bước đó còn cho thêm hai số nguyên x,yx, y với ax+by=gax + by = g, gọi là hệ số Bézout. Từ một cặp hệ số này giải được mọi bài tuyến tính trên số nguyên: nghịch đảo modulo khi modulo không nguyên tố, đồng dư ax≡b(modm)ax \equiv b \pmod m, phương trình ax+by=cax + by = c cùng toàn bộ họ nghiệm của nó.

Hệ số Bézout

Giả sử đã có x1,y1x_1, y_1 với bx1+ry1=gb x_1 + r y_1 = g, trong đó r=a mod b=a−qbr = a \bmod b = a - qb, q=⌊a/b⌋q = \lfloor a/b \rfloor. Thay rr vào: bx1+(a−qb)y1=gb x_1 + (a - qb) y_1 = g, tức a⋅y1+b⋅(x1−qy1)=ga \cdot y_1 + b \cdot (x_1 - q y_1) = g. Vậy x=y1x = y_1, y=x1−qy1y = x_1 - q y_1. Điểm dừng là b=0b = 0: a⋅1+0⋅0=a=ga \cdot 1 + 0 \cdot 0 = a = g.

Đi xuống bằng phép chia lấy dư, rồi truy ngược từng hàng: x = y₁, y = x₁ − q·y₁.
C++
ll ext(ll a, ll b, ll &x, ll &y) {
    if (!b) {
        x = 1, y = 0;
        return a;
    }
    ll x1, y1, g = ext(b, a % b, x1, y1);
    x = y1;
    y = x1 - a / b * y1;
    return g;
}

Độ sâu đệ quy như Euclid, O(log⁡min⁡(a,b))O(\log \min(a, b)). Các hệ số trả về thỏa ∣x∣≤b/g|x| \le b/g và ∣y∣≤a/g|y| \le a/g, nên không tràn khi a,ba, b vừa ll. Mọi cặp hệ số khác có dạng (x+kbg, y−kag)(x + k \frac{b}{g},\ y - k \frac{a}{g}) với kk nguyên: hiệu của hai nghiệm phải thỏa aΔx=−bΔya \Delta x = -b \Delta y, và ag,bg\frac{a}{g}, \frac{b}{g} nguyên tố cùng nhau.

Hỏi nhanh

Đã biết 35⋅1+15⋅(−2)=535 \cdot 1 + 15 \cdot (-2) = 5. Cặp nào dưới đây cũng là hệ số Bézout của (35,15)(35, 15)?

Ví dụHệ số Bézout tối ưu

Đề. Cho a,b≤109a, b \le 10^9. In hệ số Bézout x,yx, y của gcd⁡(a,b)\gcd(a, b) với ∣x∣+∣y∣|x| + |y| nhỏ nhất; hòa thì ưu tiên x≤yx \le y, rồi xx nhỏ hơn.

Lời giải. Euclid mở rộng cho một nghiệm (x,y)(x, y); mọi nghiệm khác là (x+kbg, y−kag)(x + k \frac{b}{g},\ y - k \frac{a}{g}). Nghiệm của Euclid đã có ∣x∣≤b/g|x| \le b/g và ∣y∣≤a/g|y| \le a/g, nên nghiệm tối ưu nằm trong vài nghiệm lân cận, kk từ −2-2 tới 22.

Bước 1: Euclid mở rộng. Lời gọi con cho bx1+(a mod b)y1=gb x_1 + (a \bmod b) y_1 = g. Thay a mod b=a−⌊a/b⌋ba \bmod b = a - \lfloor a/b \rfloor b rồi gom theo aa, bb được x=y1x = y_1, y=x1−⌊a/b⌋y1y = x_1 - \lfloor a/b \rfloor y_1. Đáy b=0b = 0 có a⋅1+0⋅0=aa \cdot 1 + 0 \cdot 0 = a.

C++
ll ext(ll a, ll b, ll &x, ll &y) {
    if (!b) {
        x = 1, y = 0;
        return a;
    }
    ll x1, y1, g = ext(b, a % b, x1, y1);
    x = y1;
    y = x1 - a / b * y1;
    return g;
}

Bước 2: thử các nghiệm lân cận. da, db là bước dời của họ nghiệm. So theo ∣x∣+∣y∣|x| + |y|, hòa thì so cặp (x > y, x): ưu tiên x≤yx \le y trước, xx nhỏ sau.

C++
for (ll k = -2; k <= 2; k++) {
    ll cx = x + k * da, cy = y - k * db;
    ll s1 = llabs(cx) + llabs(cy), s2 = llabs(bx) + llabs(by);
    if (s1 < s2 || (s1 == s2 && make_pair(cx > cy, cx) < make_pair(bx > by, bx))) bx = cx, by = cy;
}
Code đầy đủ
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

ll ext(ll a, ll b, ll &x, ll &y) {
    if (!b) {
        x = 1, y = 0;
        return a;
    }
    ll x1, y1, g = ext(b, a % b, x1, y1);
    x = y1;
    y = x1 - a / b * y1;
    return g;
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);

    ll a, b, x, y;
    cin >> a >> b;
    ll g = ext(a, b, x, y), da = b / g, db = a / g;
    ll bx = x, by = y;
    for (ll k = -2; k <= 2; k++) {
        ll cx = x + k * da, cy = y - k * db;
        ll s1 = llabs(cx) + llabs(cy), s2 = llabs(bx) + llabs(by);
        if (s1 < s2 || (s1 == s2 && make_pair(cx > cy, cx) < make_pair(bx > by, bx))) bx = cx, by = cy;
    }
    cout << bx << ' ' << by << '\n';
}
35 15

O(log⁡min⁡(a,b))O(\log \min(a, b)).

Nghịch đảo modulo

Nghịch đảo của aa modulo mm là xx với ax≡1(modm)ax \equiv 1 \pmod m, tức ax+my=1ax + my = 1 có nghiệm: tồn tại khi và chỉ khi gcd⁡(a,m)=1\gcd(a, m) = 1, và khi đó Euclid mở rộng cho xx ngay. Đưa về [0,m)[0, m) bằng (x % m + m) % m. Khác với lũy thừa am−2a^{m-2} (định lý Fermat), cách này đúng với mọi modulo, kể cả hợp số, và chỉ tốn O(log⁡m)O(\log m).

Ví dụNghịch đảo dương nhỏ nhất

Đề. Cho a,b≤2⋅109a, b \le 2 \cdot 10^9 nguyên tố cùng nhau. In số nguyên dương nhỏ nhất xx với ax≡1(modb)ax \equiv 1 \pmod b.

Lời giải. Euclid mở rộng cho ax+by=1ax + by = 1, tức ax≡1(modb)ax \equiv 1 \pmod b. (x % b + b) % b đưa xx về [0,b)[0, b); vì gcd⁡(a,b)=1\gcd(a, b) = 1 và b≥2b \ge 2, nghịch đảo không thể bằng 0, nên đây là nghiệm dương nhỏ nhất. Hàm ext như ví dụ trước.

Code đầy đủ
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

ll ext(ll a, ll b, ll &x, ll &y) {
    if (!b) {
        x = 1, y = 0;
        return a;
    }
    ll x1, y1, g = ext(b, a % b, x1, y1);
    x = y1;
    y = x1 - a / b * y1;
    return g;
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);

    ll a, b, x, y;
    cin >> a >> b;
    ext(a, b, x, y);
    cout << (x % b + b) % b << '\n';
}
3 11

O(log⁡b)O(\log b).

Đồng dư tuyến tính

Đồng dư ax≡b(modm)ax \equiv b \pmod m là phương trình ax−my=bax - my = b. Gọi g=gcd⁡(a,m)g = \gcd(a, m): vế trái luôn chia hết cho gg, nên vô nghiệm nếu g∤bg \nmid b. Ngược lại chia cả ba số cho gg: a′x≡b′(modm′)a' x \equiv b' \pmod{m'} với gcd⁡(a′,m′)=1\gcd(a', m') = 1, nghiệm duy nhất theo modulo m′m' là x≡b′⋅(a′)−1x \equiv b' \cdot (a')^{-1}. Theo modulo mm ban đầu có đúng gg nghiệm, cách nhau m′m'. Phép nhân b′⋅(a′)−1b' \cdot (a')^{-1} có thể tới 4⋅10184 \cdot 10^{18}, nên lấy dư trước khi nhân hoặc dùng __int128.

Hỏi nhanh

Đồng dư 4x≡2(mod6)4x \equiv 2 \pmod 6 có bao nhiêu nghiệm trong {0,1,…,5}\{0, 1, \dots, 5\}?

Ví dụĐồng dư tuyến tính

Đề. T≤105T \le 10^5 bộ a,b,m≤2⋅109a, b, m \le 2 \cdot 10^9. Với mỗi bộ in một nghiệm của ax≡b(modm)ax \equiv b \pmod m, hoặc impossible.

Lời giải. Với g=gcd⁡(a,m)g = \gcd(a, m): g∤bg \nmid b thì vô nghiệm. Ngược lại chia cả ba cho gg, được a′x≡b′(modm′)a' x \equiv b' \pmod{m'} với a′a' nguyên tố cùng nhau với m′m', nên x=a′−1b′ mod m′x = a'^{-1} b' \bmod m'. Nghiệm này nằm trong [0,m′)[0, m'), nhỏ nhất; các nghiệm khác hơn nó một bội của m′m'.

Bước 1: nghịch đảo. ext(a, m, x, y) cho ax+my=gax + my = g; chia cho gg thấy xx chính là nghịch đảo của a/ga/g theo mô-đun m/gm/g.

C++
ll g = ext(a, m, x, y);
if (b % g) {
    cout << "impossible\n";
    continue;
}

Bước 2: nhân. Hai thừa số dưới m′m' (tới 2⋅1092 \cdot 10^9), tích tới 4⋅10184 \cdot 10^{18}, sát giới hạn long long, nên ép sang __int128 cho chắc.

C++
ll mm = m / g;
ll r = (__int128)(x % mm + mm) % mm * (b / g % mm) % mm;
Code đầy đủ
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

ll ext(ll a, ll b, ll &x, ll &y) {
    if (!b) {
        x = 1, y = 0;
        return a;
    }
    ll x1, y1, g = ext(b, a % b, x1, y1);
    x = y1;
    y = x1 - a / b * y1;
    return g;
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);

    ll T;
    cin >> T;
    while (T--) {
        ll a, b, m, x, y;
        cin >> a >> b >> m;
        ll g = ext(a, m, x, y);
        if (b % g) {
            cout << "impossible\n";
            continue;
        }
        ll mm = m / g;
        ll r = (__int128)(x % mm + mm) % mm * (b / g % mm) % mm;
        cout << r << '\n';
    }
}
3
4 2 6
4 3 6
7 5 9

Mỗi bộ O(log⁡m)O(\log m).

Ví dụĐường đến ngai vàng

Đề. Vòng tròn N≤109N \le 10^9 vị trí, đang ở SS, mỗi bước tiến KK. In số bước nhỏ nhất (kể cả 0) để tới vị trí 0, hoặc −1-1.

Lời giải. Sau tt bước đang ở (S+tK) mod N(S + tK) \bmod N. Cần S+tK≡0(modN)S + tK \equiv 0 \pmod N, tức Kt≡N−S(modN)Kt \equiv N - S \pmod N: đồng dư tuyến tính của ví dụ trước với c=N−Sc = N - S. Nghiệm nhỏ nhất không âm là đáp án, vì mọi nghiệm khác hơn nó một bội của N/gN/g.

Bước 1: giải đồng dư. Ở đây m′=N/g≤109m' = N/g \le 10^9, tích hai số dưới 10910^9 vừa long long, không cần __int128.

C++
ll g = ext(k, n, x, y), c = n - s;
if (c % g) {
    cout << -1 << '\n';
    continue;
}
ll mm = n / g;
cout << (x % mm + mm) % mm * (c / g % mm) % mm << '\n';

S=0S = 0 cho c=Nc = N, chia hết cho gg và c/g mod m′=0c/g \bmod m' = 0, nên in 0 đúng như mong muốn.

Code đầy đủ
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

ll ext(ll a, ll b, ll &x, ll &y) {
    if (!b) {
        x = 1, y = 0;
        return a;
    }
    ll x1, y1, g = ext(b, a % b, x1, y1);
    x = y1;
    y = x1 - a / b * y1;
    return g;
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);

    ll T;
    cin >> T;
    while (T--) {
        ll n, s, k, x, y;
        cin >> n >> s >> k;
        ll g = ext(k, n, x, y), c = n - s;
        if (c % g) {
            cout << -1 << '\n';
            continue;
        }
        ll mm = n / g;
        cout << (x % mm + mm) % mm * (c / g % mm) % mm << '\n';
    }
}
3
10 4 3
6 1 4
7 0 3

Mỗi bộ O(log⁡N)O(\log N).

Phương trình ax+by=cax + by = c và họ nghiệm

Phương trình có nghiệm nguyên khi và chỉ khi g=gcd⁡(a,b)g = \gcd(a, b) chia hết cc. Khi đó nhân hệ số Bézout với c/gc/g được một nghiệm (x0,y0)(x_0, y_0), và mọi nghiệm là

x=x0+k⋅bg,y=y0−k⋅ag,k∈Z.x = x_0 + k \cdot \frac{b}{g}, \qquad y = y_0 - k \cdot \frac{a}{g}, \qquad k \in \mathbb{Z}.

Khi a,b>0a, b > 0, xx tăng thì yy giảm. Muốn nghiệm có xx dương nhỏ nhất: lấy x0x_0 modulo b/gb/g rồi đưa về [1,b/g][1, b/g], tính yy từ phương trình. Nếu yy khi đó vẫn dương thì có nghiệm dương, và số nghiệm dương là số bước a/ga/g còn trừ được từ yy mà vẫn dương. Với hệ số âm, đổi dấu ẩn tương ứng rồi giải với giá trị tuyệt đối.

Đường thẳng ax + by = c; chấm là các nghiệm nguyên, chấm đỏ là nghiệm dương. Đổi c sang số không chia hết cho gcd để thấy vô nghiệm.

Ví dụĐiểm nguyên trên đường thẳng

Đề. Tìm một điểm nguyên trên đường Ax+By+C=0Ax + By + C = 0 với ∣A∣,∣B∣,∣C∣≤2⋅109|A|, |B|, |C| \le 2 \cdot 10^9, hoặc in −1-1.

Lời giải. Cần Ax+By=−CAx + By = -C. Giải với giá trị tuyệt đối để ext chạy trên số không âm: ∣A∣x′+∣B∣y′=g|A| x' + |B| y' = g. Nếu g∤Cg \nmid C thì vô nghiệm.

Bước 1: nhân và đổi dấu. Nhân hai hệ số với −C/g-C/g được một nghiệm của ∣A∣x+∣B∣y=−C|A| x + |B| y = -C; đổi dấu xx khi A<0A < 0, yy khi B<0B < 0 để về đúng phương trình gốc. ∣x′∣≤∣B∣/g|x'| \le |B|/g, nhân với ∣C∣/g≤2⋅109|C|/g \le 2 \cdot 10^9, tích dưới 4⋅10184 \cdot 10^{18}, vừa long long.

C++
x *= -C / g;
y *= -C / g;
if (A < 0) x = -x;
if (B < 0) y = -y;
Code đầy đủ
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

ll ext(ll a, ll b, ll &x, ll &y) {
    if (!b) {
        x = 1, y = 0;
        return a;
    }
    ll x1, y1, g = ext(b, a % b, x1, y1);
    x = y1;
    y = x1 - a / b * y1;
    return g;
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);

    ll A, B, C, x, y;
    cin >> A >> B >> C;
    ll g = ext(llabs(A), llabs(B), x, y);
    if (C % g) {
        cout << -1 << '\n';
        return 0;
    }
    x *= -C / g;
    y *= -C / g;
    if (A < 0) x = -x;
    if (B < 0) y = -y;
    cout << x << ' ' << y << '\n';
}
6 9 -3

O(log⁡min⁡(∣A∣,∣B∣))O(\log \min(|A|, |B|)).

Ví dụMẫu Phương Trình Nghiệm Nguyên

Đề. T≤2⋅105T \le 2 \cdot 10^5 phương trình ax+by=cax + by = c với a,b,c≤109a, b, c \le 10^9. Không có nghiệm nguyên thì in −1-1; có nghiệm nhưng không có nghiệm dương thì in xx dương nhỏ nhất và yy dương nhỏ nhất (có thể từ hai nghiệm khác nhau); có nghiệm dương thì in số nghiệm dương, xx nhỏ nhất, yy nhỏ nhất, xx lớn nhất, yy lớn nhất.

Lời giải. Đặt p=b/gp = b/g, q=a/gq = a/g: mỗi bước tăng xx thêm pp thì yy giảm qq. Lấy nghiệm có xx dương nhỏ nhất; ứng với nó yy lớn nhất. Từ đó đếm được còn bao nhiêu bước mà yy vẫn dương.

Bước 1: xx dương nhỏ nhất. Nhân x0x_0 với c/gc/g theo mô-đun pp, rồi đưa về [1,p][1, p]. Tích tới 101810^{18}, vẫn vừa long long.

C++
ll p = b / g, q = a / g;
ll x = (x0 % p) * (c / g % p) % p;
x = (x % p + p) % p;
if (!x) x = p;
ll y = (c - a * x) / b;

(c - a * x) / b chia hết vì (x,y)(x, y) thuộc họ nghiệm.

Bước 2: có nghiệm dương. y≥1y \ge 1 thì số nghiệm dương là số lần còn giảm yy đi qq mà vẫn ≥1\ge 1, cộng chính nghiệm hiện tại: ⌊(y−1)/q⌋+1\lfloor (y - 1)/q \rfloor + 1. Nghiệm cuối cho yy nhỏ nhất và xx lớn nhất.

C++
ll cnt = (y - 1) / q + 1;
cout << cnt << ' ' << x << ' ' << y - (cnt - 1) * q << ' ' << x + (cnt - 1) * p << ' ' << y << '\n';

Bước 3: không có nghiệm dương. Không nghiệm nào cả hai cùng dương; yy dương nhỏ nhất (của một nghiệm khác) là yy đưa về [1,q][1, q].

C++
ll ym = (y % q + q) % q;
if (!ym) ym = q;
cout << x << ' ' << ym << '\n';
Code đầy đủ
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

ll ext(ll a, ll b, ll &x, ll &y) {
    if (!b) {
        x = 1, y = 0;
        return a;
    }
    ll x1, y1, g = ext(b, a % b, x1, y1);
    x = y1;
    y = x1 - a / b * y1;
    return g;
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);

    ll T;
    cin >> T;
    while (T--) {
        ll a, b, c, x0, y0;
        cin >> a >> b >> c;
        ll g = ext(a, b, x0, y0);
        if (c % g) {
            cout << -1 << '\n';
            continue;
        }
        ll p = b / g, q = a / g;
        ll x = (x0 % p) * (c / g % p) % p;
        x = (x % p + p) % p;
        if (!x) x = p;
        ll y = (c - a * x) / b;
        if (y >= 1) {
            ll cnt = (y - 1) / q + 1;
            cout << cnt << ' ' << x << ' ' << y - (cnt - 1) * q << ' ' << x + (cnt - 1) * p << ' ' << y << '\n';
        } else {
            ll ym = (y % q + q) % q;
            if (!ym) ym = q;
            cout << x << ' ' << ym << '\n';
        }
    }
}
4
2 3 12
4 6 5
4 6 20
3 5 18

Mỗi phương trình O(log⁡min⁡(a,b))O(\log \min(a, b)).

Khi đi thi

  • Nghịch đảo modulo hợp số, đồng dư ax≡b(modm)ax \equiv b \pmod m, phương trình ax+by=cax + by = c: Euclid mở rộng. Luôn kiểm g∣cg \mid c trước.
  • Nghiệm “nhỏ nhất không âm” là lấy dư theo bước b/gb/g của họ nghiệm, không theo bb; viết (x % p + p) % p vì phép % của C++ giữ dấu số bị chia.
  • Tích của hai số tới 10910^9 đã cần ll; tới 101210^{12} hay 101810^{18} thì nhân bằng __int128 hoặc lấy dư trước mỗi phép nhân.

Tóm tắt

  • x=y1x = y_1, y=x1−⌊a/b⌋y1y = x_1 - \lfloor a/b \rfloor y_1; điểm dừng (1,0)(1, 0) khi b=0b = 0.
  • Họ hệ số Bézout là (x+kb/g,y−ka/g)(x + k b/g, y - k a/g).
  • Nghịch đảo của aa modulo mm tồn tại khi gcd⁡(a,m)=1\gcd(a, m) = 1 và là hệ số xx của ax+my=1ax + my = 1.
  • ax≡b(modm)ax \equiv b \pmod m có nghiệm khi g∣bg \mid b; nghiệm duy nhất theo modulo m/gm/g.
  • ax+by=cax + by = c: một nghiệm từ Bézout nhân c/gc/g, đếm nghiệm dương bằng cách đưa xx về nhỏ nhất rồi đếm số bước a/ga/g còn trừ được từ yy.

Bài tập

1
Phương trình Ax + By = Ccanuc80k4701In một nghiệm bất kỳ của Ax+By=CAx + By = C, xử lý dấu của AA, BB như bài điểm nguyên trên đường thẳng.
LQDOJ
2
Hai loại nghịch đảocanuc80k4703Nghịch đảo cộng là (N−A) mod N(N - A) \bmod N; nghịch đảo nhân bằng Euclid mở rộng khi gcd⁡(A,N)=1\gcd(A, N) = 1, NN tới 101210^{12} nên dùng __int128 khi nhân.
LQDOJ
3
Máy tính modulocanuc80k4705Bốn phép theo modulo nn tới 101810^{18}: nhân bằng __int128, chia là nhân với nghịch đảo từ Euclid mở rộng, không có nghịch đảo thì −1-1.
LQDOJ
4
Cuộc hẹn trên vòng tròncanuc80k4707Hai con ếch gặp nhau sau tt bước khi x+mt≡y+nt(modL)x + mt \equiv y + nt \pmod L: đồng dư (m−n)t≡y−x(m - n) t \equiv y - x, nghiệm dương nhỏ nhất.
LQDOJ
5
Tam giác đơn vịcanuc80k4709Diện tích tam giác bằng 1 là ∣Xb−Ya∣=2|Xb - Ya| = 2; giải Xb−Ya=±2Xb - Ya = \pm 2 bằng Euclid mở rộng với X,YX, Y tới 101710^{17}, nhân bằng __int128.
LQDOJ
6
Chia kẹocanuc80k4710Cần Cy−Kx=1C y - K x = 1 với x,y≥1x, y \ge 1 trong giới hạn: yy là nghịch đảo của CC modulo KK, chỉnh về yy nhỏ nhất thỏa Cy>KCy > K.
LQDOJ
7
Thanh ghi tuần hoàncanuc80k4711Vòng lặp chạy xx lần khi A+Cx≡B(mod2k)A + Cx \equiv B \pmod{2^k}; đồng dư tuyến tính với modulo 2k2^k, nghiệm nhỏ nhất không âm hoặc FOREVER.
LQDOJ
8
Chở khách tối ưucanuc80k4712Họ nghiệm (m1,m2)(m_1, m_2) của n1m1+n2m2=Nn_1 m_1 + n_2 m_2 = N; chi phí tuyến tính theo tham số kk nên chỉ cần thử hai đầu của khoảng kk giữ cả hai số không âm.
LQDOJ
9
Đếm nghiệm trong hình chữ nhậtcanuc80k4713Đếm nghiệm trong hình chữ nhật: khoảng kk cho xx nằm trong [x1,x2][x_1, x_2] giao với khoảng kk cho yy nằm trong [y1,y2][y_1, y_2]; xét riêng a=0a = 0 hoặc b=0b = 0.
LQDOJ
10
Hai lịch tuần hoàncanuc80k4715Giá trị chung của hai dãy là nghiệm của n+mi=k+a+ajn + mi = k + a + aj với i,j≥0i, j \ge 0; giải phương trình hai ẩn, xử lý riêng khi một bước bằng 0.
LQDOJ
11
Giao của hai cấp số cộngcanuc80k4716Số chung của hai cấp số cộng là một cấp số cộng bước lcm(a1,a2)\mathrm{lcm}(a_1, a_2) khi hệ đồng dư có nghiệm; tìm phần tử đầu không nhỏ hơn max⁡(b1,b2,L)\max(b_1, b_2, L) rồi đếm tới RR.
LQDOJ
12
Ba loại quàcanuc80k4717Duyệt zz từ 0 tới P/CP / C; với mỗi zz đếm nghiệm không âm của Ax+By=P−CzAx + By = P - Cz bằng họ nghiệm.
LQDOJ
13
Ghép hai đồng dưcanuc80k4718Gộp hai đồng dư x≡a(modn)x \equiv a \pmod n, x≡b(modm)x \equiv b \pmod m: a+nt≡b(modm)a + nt \equiv b \pmod m là đồng dư tuyến tính theo tt; nghiệm theo modulo lcm(n,m)\mathrm{lcm}(n, m).
LQDOJ
14
Chuyến tàu và giấc ngủcanuc80k4719Thử mọi cặp phần dư (thời điểm tàu tới, thời điểm thức) trong hai khoảng nhỏ; mỗi cặp là hệ hai đồng dư, gộp bằng Euclid mở rộng, lấy nhỏ nhất.
LQDOJ
15
Chuỗi tích tiền tố tối ưucanuc80k4720Nhóm các phần dư được phép theo gcd⁡\gcd với mm; nhóm dd đi được tới nhóm d′d' khi d∣d′d \mid d', đường dài nhất trên các ước; bước từ pp tới p′p' là đồng dư p⋅a≡p′(modm)p \cdot a \equiv p' \pmod m.
LQDOJ

Đọc thêm