同余代数

同余代数

定理相关

  • 费马小定理:若 \(p\) 为质数且 \(a \bot p\) ,则 \(a^{p - 1} \equiv 1 \pmod{p}\)

  • 欧拉定理:若 \(a \bot m\) ,则 \(a^{\varphi(m)} \equiv 1 \pmod{m}\)

    扩展形式:

    \[\]

    \begin{cases}
    a^{b \bmod \varphi(m)}, &\gcd(a, m) = 1 \
    a^b, &\gcd(a, m) \ne 1, b < \varphi(m) \
    a^{(b \bmod \varphi(m)) + \varphi(m)}, &\gcd(a, m) \ne 1, b \ge \varphi(m)
    \end{cases}
    \pmod{m}

    \[\]

  • Wilson 定理:对于素数 \(p\) ,有 \((p - 1)! \equiv -1 \pmod{p}\)

  • Kummer 定理:

    • \(p\)\(n!\) 的幂次等于 \(n\) 减去 \(n\)\(p\) 进制下的各位数字和再除以 \(p - 1\)
      • \(p = 2\) 时幂次为 \(n - \mathrm{popcount}(n)\)
    • \(p\)\(\binom{n}{m}\) 的幂次等于 \(p\) 进制下 \(n - m\) 需要借位的次数。
    • \(p\)\(\binom{n + m}{n}\) 的幂次等于 \(p\) 进制下 \(n + m\) 的进位次数。
      • \(\binom{n + m}{m} \bmod 2 = [n \operatorname{and} m = 0]\)

欧几里得相关

exgcd

先引入裴蜀定理:不定方程 \(ax + by = c\) 有整数解当且仅当 \(\gcd(a, b) \mid c\)

exgcd 通常用于求解不定方程 \(ax + by = \gcd(a, b)\) 的一组解。由裴蜀定理,该方程一定有解。

\(d = \gcd(a, b) = \gcd(b, a \bmod b)\) ,因此方程 \(bx + (a \bmod b) y = d\) 一定有解,设其一组解为 \(x = x', y = y'\) ,则:

\[\begin{aligned} ax + by = d &= b x' + (a \bmod b) y' \\ &= b x' + (a - b \times \lfloor \frac{a}{b} \rfloor) y' \\ &= a y' + b (x' - \lfloor \frac{a}{b} \rfloor y') \end{aligned} \]

因此可以不断递归,当 \(b = 0\)\(x = 1, y = 0\) 即为一组解。

时间复杂度 \(O(\log V)\)

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

P5656 【模板】二元一次不定方程 (exgcd)

解不定方程 \(ax + by = c\)

  • 若无整数解则输出 \(-1\)
  • 否则若存在正整数解,则输出:正整数解的数量、所有正整数解中 \(x\) 的最小值、所有正整数解中 \(y\) 的最小值、所有正整数解中 \(x\) 的最大值、所有正整数解中 \(y\) 的最大值。
  • 否则输出所有整数解中 \(x\) 的最小正整数值、 \(y\) 的最小正整数值。

\(a, b, c \le 10^9\)

对于不定方程:

\[ax + by = c \]

\(\gcd(a, b) \nmid c\) 则无解,否则可以用 exgcd 求出不定方程 \(ax + by = \gcd(a,b)\) 的一组整数解,记为 \(\begin{cases} x = x_0 \\ y = y_0 \end{cases}\) ,由此可以得到该方程的一特解:

\[\begin{cases} x_1 = \dfrac{x_0 c}{\gcd(a, b)} \\ y_1 = \dfrac{y_0 c}{\gcd(a, b)} \end{cases} \]

考虑构造原方程整数通解形式,即:

\[\begin{cases} x = x_1 + kb \\ y = y_1 - ka \end{cases} \]

需要保证 \(kb, ka\) 均为整数。令当 \(k\) 取到最小可能的正值时的 \(k_x = kb, k_y = ka\) ,那么有通解形式:

\[\begin{cases} x = x_1 + s k_x \\ y = y_1 - s k_y \end{cases} \]

其中 \(s\) 为任意整数。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;

ll exgcd(ll a, ll b, ll &x, ll &y) {
    if (b) {
        ll g = exgcd(b, a % b, y, x);
        return y -= a / b * x, g;
    } else
        return x = 1, y = 0, a;
}

signed main() {
    int T;
    scanf("%d", &T);
    
    while (T--) {
        ll a, b, c;
        scanf("%lld%lld%lld", &a, &b, &c);
        ll x, y, g = exgcd(a, b, x, y);
        
        if (c % g)
            puts("-1");
        else {
            x *= c / g, y *= c / g;
            ll p = b / g, q = a / g, k;
            
            if (x < 0)
                k = ceil((1.0 - x) / p), x += p * k, y -= q * k;
            else
                k = (x - 1) / p, x -= p * k, y += q * k;
            
            if (y > 0) {
                printf("%lld %lld %lld %lld %lld\n", (y - 1) / q + 1, x, (y - 1) % q + 1, x + (y - 1) / q * p, y);
            } else
                printf("%lld %lld\n", x, y + q * (ll)ceil((1.0 - y) / q));
        }
    }
    
    return 0;
}

类欧几里得算法

P5170 【模板】类欧几里得算法

给定 \(n, a, b, c\) ,求:

\[\begin{aligned} f(a, b, c, n) &= \sum_{i = 0}^n \lfloor \frac{ai + b}{c} \rfloor \\ g(a, b, c, n) &= \sum_{i = 0}^n \lfloor \frac{ai + b}{c} \rfloor i \\ h(a, b, c, n) &= \sum_{x = 0}^n \lfloor \frac{a x + b}{c} \rfloor^2 \end{aligned} \]

\(n, a, b, c \le 10^9\)

\(f(a, b, c, n)\)

考虑先将 \(a \ge c\)\(b \ge c\) 的情况转化为 \(a, b < c\) 的情况:

\[\begin{aligned} f(a, b, c, n) &= \sum_{i = 0}^n \lfloor \frac{ai + b}{c} \rfloor \\ &= \sum_{i = 0}^n \lfloor \frac{(a \bmod c) i + (a - a \bmod c) i + (b \bmod c) + (b - b \bmod c)}{c} \rfloor \\ &= \sum_{i = 0}^n (\lfloor \frac{(a \bmod c) i + (b \bmod c)}{c} \rfloor + \frac{(a - a \bmod c) i}{c} + \frac{b - b \bmod c}{c}) \\ &= \sum_{i = 0}^n (\lfloor \frac{(a \bmod c) i + (b \bmod c)}{c} \rfloor + \lfloor \frac{a}{c} \rfloor i + \lfloor \frac{b}{c} \rfloor) \\ &= \lfloor \frac{a}{c} \rfloor \times \frac{n(n + 1)}{2} + (n + 1) \lfloor \frac{b}{c} \rfloor + \sum_{i = 0}^n \lfloor \frac{(a \bmod c) i + (b \bmod c)}{c} \rfloor \\ &= \lfloor \frac{a}{c} \rfloor \times \frac{n(n + 1)}{2} + (n + 1) \lfloor \frac{b}{c} \rfloor + f(a \bmod c, b \bmod c, c, n) \end{aligned} \]

下面考虑 \(a, b < c\) 的情况,记 \(m = \lfloor \frac{an + b}{c} \rfloor\) ,则:

\[\begin{aligned} f(a, b, c, n) &= \sum_{i = 0}^n \lfloor \frac{ai + b}{c} \rfloor \\ &=\sum_{i = 0}^n \sum_{j = 0} ^{\lfloor \frac{ai + b}{c} \rfloor - 1} 1 \\ &= \sum_{j = 0}^{m - 1} \sum_{i = 0}^n [j < \lfloor \frac{ai + b}{c} \rfloor] \\ &= \sum_{j = 0}^{m - 1} \sum_{i = 0}^n [j + 1 \le \frac{ai + b}{c}] \\ &= \sum_{j = 0}^{m - 1} \sum_{i = 0}^n [cj + c - b \le ai] \\ &= \sum_{j = 0}^{m - 1} \sum_{i = 0}^n [cj + c - b - 1 < ai] \\ &= \sum_{j = 0}^{m - 1} \sum_{i = 0}^n [\lfloor \frac{cj + c - b - 1}{a} \rfloor < i] \\ &= \sum_{j = 0}^{m - 1} n -\lfloor \frac{cj + c - b - 1}{a} \rfloor \\ &= nm - f(c, c - b - 1, a, m - 1) \end{aligned} \]

不难发现这里把 \(a\)\(c\) 的位置交换了,这个过程类似于辗转相除法,因此时间复杂度为 \(O(\log V)\)

\(g(a, b, c, n)\)

同样考虑先将 \(a \ge c\)\(b \ge c\) 的情况转化为 \(a, b < c\) 的情况,类似可以得出:

\[\begin{aligned} g(a, b, c, n) &= \sum_{i = 0}^n \lfloor \frac{ai + b}{c} \rfloor i \\ &= \sum_{i = 0}^n (\lfloor \frac{(a \bmod c) i^2 + (b \bmod c) i}{c} \rfloor + \lfloor \frac{a}{c} \rfloor i^2 + \lfloor \frac{b}{c} \rfloor i) \\ &= \frac{n (n + 1) (2n + 1)}{6} \lfloor \frac{a}{c} \rfloor + \frac{n (n + 1)}{2} \lfloor \frac{b}{c} \rfloor + \sum_{i = 0}^n \lfloor \frac{(a \bmod c) i^2 + (b \bmod c) i}{c} \rfloor \\ &= \frac{n (n + 1) (2n + 1)}{6} \lfloor \frac{a}{c} \rfloor + \frac{n (n + 1)}{2} \lfloor \frac{b}{c} \rfloor + g(a \bmod c, b \bmod c, c, n) \end{aligned} \]

下面考虑 \(a, b < c\) 的情况,记 \(m = \lfloor \frac{an + b}{c} \rfloor, t = \lfloor \frac{cj + c - b - 1}{a} \rfloor\) ,则:

\[\begin{aligned} g(a, b, c, n) &= \sum_{j = 0}^{m - 1} \sum_{i = 0}^n [i > t] i \\ &= \sum_{j = 0}^{m - 1} \frac{(t + 1 + n) (n - t)}{2} \\ &= \sum_{j = 0}^{m - 1} \frac{1}{2}(n(n + 1) - (t^2 + t)) \\ &= \frac{1}{2} \left( mn(n + 1) - \sum_{i = 0}^{m - 1} t^2 - \sum_{i = 0}^{m - 1} t \right) \\ &= \dfrac{1}{2} (mn(n + 1) - h(c, c - b - 1, a, m - 1) - f(c, c - b - 1, a, m - 1)) \end{aligned} \]

\(h(a, b, c, n)\)

同样考虑先将 \(a \ge c\)\(b \ge c\) 的情况转化为 \(a, b < c\) 的情况,类似可以得出:

\[\begin{aligned} h(a, b, c, n) &= h(a \bmod c, b \bmod c, c, n) \\ &+ 2 \lfloor \frac{b}{c} \rfloor f(a \bmod c, b \bmod c, c, n) \\ &+ 2 \lfloor \frac{a}{c} \rfloor g(a \bmod c, b \bmod c, c, n) \\ &+ \lfloor \frac{a}{c} \rfloor^2 \frac{n (n + 1) (2n + 1)}{6} \\ &+ \lfloor \frac{b}{c} \rfloor^2 (n + 1) \\ &+ \lfloor \frac{a}{c} \rfloor \lfloor \frac{b}{c} \rfloor n (n + 1) \end{aligned} \]

下面考虑 \(a, b < c\) 的情况,记 \(m = \lfloor \frac{an + b}{c} \rfloor, t = \lfloor \frac{cj + c - b - 1}{a} \rfloor\) 。为了避免出现求和号相乘的情况,考虑将平方化为:

\[n^2 = (2 \sum_{i = 0}^n i) - n \]

则:

\[\begin{aligned} h(a, b, c, n) &= \sum_{x = 0}^n \lfloor \frac{a x + b}{c} \rfloor^2 \\ &= \sum_{x = 0}^n [(2 \sum_{j = 1}^{\lfloor \frac{a x + b}{c} \rfloor} j) - \lfloor \frac{a x + b}{c} \rfloor] \\ &= (2 \sum_{i = 0}^n \sum_{j = 1}^{\lfloor \frac{a x + b}{c} \rfloor} j) - f(a, b, c, n) \end{aligned} \]

化简前面一部分:

\[\begin{aligned} 2 \sum_{i = 0}^n \sum_{j = 1}^{\lfloor \frac{ai + b}{c} \rfloor} j &= 2 \sum_{i = 0}^n \sum_{j = 0}^{\lfloor \frac{ai + b}{c} \rfloor - 1} (j + 1) \\ &= \sum_{j = 0}^{m - 1} (j + 1) \sum_{i = 0}^n [j < \lfloor \frac{ai + b}{c} \rfloor] \\ &= \sum_{j = 0}^{m - 1} (j + 1) \sum_{i = 0}^n [i > t] \\ &= \sum_{j = 0}^{m - 1} (j + 1)(n - t) \\ &= \frac{n m (m + 1)}{2} - \sum_{j = 0}^{m - 1} (j + 1) \lfloor \frac{cj + c - b - 1}{a} \rfloor \\ &= \frac{n m (m + 1)}{2} - g(c, c - b - 1, a, m - 1) - f(c, c - n - 1, a, m - 1) \end{aligned} \]

整理得到:

\[h(a, b, c, n) = n m (m + 1) - 2g (c, c - b - 1, a, m - 1) - 2f(c, c - b - 1, a, m - 1) - f(a, b, c, n) \]

实现

#include <bits/stdc++.h>
using namespace std;
const int Mod = 998244353, inv2 = (Mod + 1) / 2, inv6 = 166374059;

struct Node {
    int f, g, h;
};

inline int add(int x, int y) {
    x += y;
    
    if (x >= Mod)
        x -= Mod;
    
    return x;
}

inline int dec(int x, int y) {
    x -= y;
    
    if (x < 0)
        x += Mod;
    
    return x;
}

inline Node calc(int a, int b, int c, int n) {
    int s1 = 1ll * n * (n + 1) % Mod * inv2 % Mod, 
        s2 = 1ll * n * (n + 1) % Mod * (n * 2 + 1) % Mod * inv6 % Mod;

    if (!a) {
        Node ans;
        ans.f = 1ll * (n + 1) * (b / c) % Mod;
        ans.g = 1ll * s1 * (b / c) % Mod;
        ans.h = 1ll * (n + 1) * (b / c) % Mod * (b / c) % Mod;
        return ans;
    }

    if (a >= c || b >= c) {
        Node res = calc(a % c, b % c, c, n), ans;
        ans.f = add(add(1ll * (a / c) * s1 % Mod, 1ll * (b / c) * (n + 1) % Mod), res.f);
        ans.g = add(add(1ll * s2 * (a / c) % Mod, 1ll * s1 * (b / c) % Mod), res.g);
        ans.h = add(add(add(res.h, 2ll * (b / c) * res.f % Mod), 2ll * (a / c) * res.g % Mod), 
                add(1ll * (a / c) * (a / c) % Mod * s2 % Mod, 
                add(1ll * (b / c) * (b / c) % Mod * (n + 1) % Mod, 
                    1ll * (a / c) * (b / c) % Mod * n % Mod * (n + 1) % Mod)));
        return ans;
    }

    int m = (1ll * a * n + b) / c;
    Node res = calc(c, c - b - 1, a, m - 1), ans;
    ans.f = dec(1ll * n * m % Mod, res.f);
    ans.g = 1ll * dec(dec(1ll * m * n % Mod * (n + 1) % Mod, res.h), res.f) * inv2 % Mod;
    ans.h = dec(dec(dec(1ll * n * m % Mod * (m + 1) % Mod, 2ll * res.g % Mod), 2ll * res.f % Mod), ans.f);
    return ans;
}

signed main() {
    int T;
    scanf("%d", &T);

    while (T--) {
        int n, a, b, c;
        scanf("%d%d%d%d", &n, &a, &b, &c);
        Node ans = calc(a, b, c, n);
        printf("%d %d %d\n", ans.f, ans.h, ans.g);
    }

    return 0;
}

线性同余方程组

线性同余方程组形如:

\[\begin{cases} x &\equiv a_1 \pmod{m_1} \\ x &\equiv a_2 \pmod{m_2} \\ &\vdots \\ x &\equiv a_k \pmod{m_k} \end{cases} \]

CRT

P1495 【模板】中国剩余定理(CRT)/ 曹冲养猪

前置条件:\(m\) 两两互质。

先求出 \(M = \prod_{i = 1}^k m_i\) ,对于第 \(i\) 个方程,求出:

  • \(p_i = \frac{M}{m_i}\)
  • \(p_i\) 在模 \(m_i\) 意义下的逆元 \(p_i^{-1}\)
  • \(c_i = p_i p_i^{-1} \bmod M\)

方程组在模 \(M\) 意义下的唯一解为 \(x = \sum_{i = 1}^k a_i c_i \pmod{M}\)

证明:只需证明上述算法解出的 \(x\) 均满足每一个方程即可。

\(i \not = j\) 时,显然有 \(p_j \equiv 0 \pmod{m_i}\) ,故 \(c_j \equiv p_j \equiv 0 \pmod{m_i}\) ,又因为 \(c_i \equiv p_i (p_i^{-1} \bmod m_i) \equiv 1 \pmod{m_i}\) ,所以有:

\[\begin{aligned} x &\equiv \sum_{j = 1}^k a_j c_j &\pmod{m_i} \\ &\equiv a_i c_i &\pmod{m_i} \\ &\equiv a_i p_i (p_i^{-1} \bmod m_i) &\pmod{m_i} \\ &\equiv a_i &\pmod{m_i} \end{aligned} \]

因此上述算法解出的 \(x\) 均满足每一个方程。

inline ll CRT() {
    ll M = 1;

    for (int i = 1; i <= n; ++i)
        M *= m[i];

    ll res = 0;

    for (int i = 1; i <= n; ++i)
        res = (res + mul(mul(a[i], M / m[i], M), inv(M / m[i], m[i]), M)) % M;

    return res;
}

exCRT

P4777 【模板】扩展中国剩余定理(EXCRT)

无前置条件限制。

考虑将两个同余方程合并为一个同余方程,设两个方程分别为:

\[\begin{cases} x &\equiv a_1 \pmod{m_1} \\ x &\equiv a_2 \pmod{m_2} \end{cases} \]

转化为不定方程:

\[x = m_1 p + a_1 = m_2 q + a_2 \]

其中 \(p, q \in \mathbb{Z}\) ,则:

\[m_1 p - m_2 q = a_2 - a_1 \]

由裴蜀定理,当 \(\gcd(m_1, m_2) \nmid (a_2 - a_1)\) 时方程无解,否则用 exgcd 求出一组可行解 \(p, q\) ,则 \(x \equiv m_1 p + a_1 \pmod{\operatorname{lcm}(m_1, m_2)}\)

推广到多个方程,类似地按上述过程两两合并即可。

inline pair<ll, ll> merge(pair<ll, ll> a, pair<ll, ll> b) {
    ll a1 = a.first, m1 = a.second, a2 = b.first, m2 = b.second;
    ll x, y, g = exgcd(m1, m2, x, y), l = m1 / g * m2, c = ((a2 - a1) % l + l) % l;

    if (c % g)
        return make_pair(-1ll, -1ll);

    return make_pair((a1 + mul(mul(x, c / g, l), m1, l)) % l, l);
}

阶与原根

若满足同余式 \(a^n \equiv 1 \pmod{m}\) 的最小正整数 \(n\) 存在,则称 \(n\)\(a\)\(m\) 的阶,记作 \(\delta_m(a)\)

阶的性质:

  • \(a, a^2, \cdots, a^{\delta_m(a)}\)\(m\) 两两不同余。
  • \(a^n \equiv 1 \pmod{m}\) ,则 \(\delta_m(a) \mid n\)
    • 推论:若 \(a^p \equiv a^q \pmod{m}\) ,则 \(p \equiv q \pmod{\delta_m(a)}\)
  • \(\gcd(a, m) = \gcd(b, m) = 1\) ,则 \(\delta_m(a, b) = \delta_m(a) \delta_m(b)\) 的充要条件是 \(\gcd(\delta_m(a), \delta_m(b)) = 1\)
  • \(\gcd(a, m) = 1\) ,则 \(\delta_m(a^k) = \frac{\delta_m(a)}{\gcd(\delta_m(a), k)}\)

\(\gcd(g, m) = 1\)\(\delta_m(g) = \varphi(m)\) ,则称 \(g\) 为模 \(m\) 的原根。

原根的性质:

  • 原根存在定理:\(m\) 存在原根当且仅当 \(m = 2, 4, p^\alpha, 2p^\alpha\) ,其中 \(p\) 为奇素数。
  • 原根个数:若 \(m\) 有原根,则数量为 \(\varphi(\varphi(m))\)
  • 原根判定定理:设 \(m \ge 3\)\(\gcd(g, m) = 1\) ,则 \(g\) 是模 \(m\) 的原根的充要条件是 \(\varphi(m)\) 的每个质因子 \(p\) 均满足 \(g^{\frac{\varphi(m)}{p}} \not \equiv 1 \pmod{m}\)
  • 最小原根范围估计:\(p\) 为素数时,\(g_p = \Omega(\log p)\)

离散对数问题

离散对数方程:

\[a^x \equiv b \pmod{p} \]

其中 \(x\) 即为模 \(p\) 意义下的 \(\log_a b\)

BSGS

P3846 [TJOI2007] 可爱的质数/【模板】BSGS

前置条件:\(a \bot p\)

\(x=A \times \lceil \sqrt{p} \rceil - B\) ,其中 \(0 \le A,B \le \lceil \sqrt{p} \rceil\) ,则:

\[\begin{align} a^{A \times \lceil \sqrt{p} \rceil - B} &\equiv b \pmod{p} \\ a^{A \times \lceil \sqrt{p} \rceil} &\equiv b \times a^B \pmod{p} \end{align} \]

考虑记录 \(b \times a^B\) 的所有取值,再枚举所有的 \(A\) ,寻找满足等式的 \(B\) 是否存在即可,时间复杂度 \(O(\sqrt{p})\)

inline int BSGS(int a, int b, int p) {
    a %= p, b %= p;
    map<int, int> mp;
    int t = 1, L = ceil(sqrt(p));
    mp[b] = 0;

    for (int i = 1; i <= L; ++i)
        t = 1ll * t * a % p, mp[1ll * b * t % p] = i;

    for (int i = 1, u = t; i <= L; ++i, u = 1ll * u * t % p)
        if (mp.find(u) != mp.end())
            return 1ll * i * L - mp[u];

    return -1;
}

exBSGS

P4195 【模板】扩展 BSGS/exBSGS

无前置条件。

\(g = \gcd(a, p)\) ,若 \(g \nmid b\) 则原方程无解。

证明:若方程有解,不妨设 \(a '= \frac{a}{g}, p' = \frac{p}{g}\) ,则 \(a = a'g, p = p'g\) 。带入方程得到 \((a'g)^x \equiv b \pmod{p'g}\) ,转化为不定方程 \(a'^x g^x + y p'g = b\) ,即 \(a'x g^{x - 1} + yp' = \frac{b}{g}\) 。由于 \(a'xg^{x-1} + yp'\) 为整数,因此 \(g \mid b\)

\(g\) 带入原方程,得:

\[a^{x - 1} \times \frac{a}{g} \equiv \frac{b}{g} \pmod{\dfrac{p}{g}} \]

此时 \(a, \frac{p}{g}\) 仍有可能不互质,不断进行上述操作直到 \(a \bot \frac{p}{g}\)

\(G = \prod g\)\(k\) 为化简次数,带入原方程可得:

\[\frac{a^k}{G} \times a^{x - k} \equiv \frac{b}{G} \pmod{\frac{p}{G}} \]

由于 \(a \bot \frac{p}{G}\) ,因此 \(\frac{a^k}{G} \bot \frac{p}{G}\) ,从而可以将 \(\frac{a^k}{G}\) 扔到方程右边,之后用普通 BSGS 解决即可。

注意这里没有排除解 \(\le k\) 的情况,需要额外枚举判断。

inline int exBSGS(int a, int b, int p) {
    a %= p, b %= p;
    
    if (b == 1 || p == 1)
        return 0;

    int g = __gcd(a, p), k = 0, D = 1;

    while (g > 1) {
        if (b % g)
            return -1;

        ++k, b /= g, p /= g, D = 1ll * D * (a / g) % p;

        if (D == b)
            return k;

        g = __gcd(a, p);
    }
    
    int f = BSGS(a, 1ll * b * inv(D, p) % p, p);
    return ~f ? f + k : -1;
}

二次剩余

P5491 【模板】二次剩余

二次剩余方程形如:

\[x^2 \equiv n \pmod{p} \]

下面讨论 \(p\) 为奇素数且 \(n \ne 0\) 的情况,不难发现任意一对相反数都对应一个二次剩余,因此方程在 \([0, p - 1]\) 范围内有两个解或无解。

欧拉准则

欧拉准则用于快速判断一个数是不是二次剩余,即上述方程是否有解。

由费马小定理 \(n^{p - 1} \equiv p \pmod{p}\) ,得到 \(n^{2(\frac{p - 1}{2})} - 1 \equiv 0 \pmod{p}\) ,即 \(n^{\frac{p - 1}{2}} = \pm 1\)

\(n\) 是二次剩余,则 \(n^{\frac{p - 1}{2}} \equiv (x^2)^{\frac{p - 1}{2}} \equiv x^{p - 1} \equiv 1 \pmod{p}\)

\(n^{\frac{p - 1}{2}} \equiv 1 \pmod{p}\) ,设 \(n = g^k\) ,其中 \(g\)\(p\) 的原根,则 \(g^{\frac{k (p - 1)}{2}} \equiv 1 \pmod{p}\) ,由于 \(g\) 是原根,则必有 \(p - 1 | \frac{k (p - 1)}{2}\) ,即 \(k\) 一定是偶数,那么 \(x = g^{\frac{k}{2}}\) 即是 \(n\) 开根的结果,因此 \(n\) 是二次剩余。

因此得到结论:

  • \(n^{\frac{p - 1}{2}} \equiv 1 \pmod{p}\)\(n\) 是二次剩余的充要条件。
  • \(n^{\frac{p - 1}{2}} \equiv -1 \pmod{p}\)\(n\) 是非二次剩余的充要条件。

Cipolla 算法

先找到一个 \(a\) 满足 \(a^2 - n\) 是非二次剩余,由于非二次剩余的数量接近一半,可以通过随机后检验的方式期望 \(2\) 次找到一个 \(a\)

接下来类比实数域到复数域的推广,定义 \(i^2 \equiv a^2 - n \pmod{p}\) ,然后将所有数表示为 \(A + Bi\) 的形式。

引理一 :\(i^p \equiv -i \pmod{p}\)

证明:\(i^p \equiv i(i^2)^{\frac{p - 1}{2}} \equiv i(a^2 - n)^{\frac{p - 1}{2}} \equiv -i \pmod{p}\)

引理二:\((A + B)^p \equiv A^p + B^p \pmod{p}\)

证明:二项式定理展开后,由于 \(p\) 是质数,除了 \(\binom{p}{0}, \binom{p}{p}\) 外的组合数分子上的阶乘无法消除,模 \(p\) 都为 \(0\) ,故剩下 \(\binom{p}{0} A^0 B^p + \binom{p}{p} A^p B^0 = A^p + B^p\)

定理 : \((a + i)^{p + 1} \equiv n\)

证明:\((a + i)^{p + 1} \equiv (a^p + i^p)(a + i) \equiv (a + i)(a - i) \equiv a^2 - i^2 \equiv n \pmod{p}\)

那么 \((a + i)^{\frac{p + 1}{2}}\) 即是一个解,其相反数是另一个解。接下来只需证明 \((a + i)^{\frac{p + 1}{2}}\) 虚部为 \(0\)

证明:假设存在 \((A + Bi)^2 \equiv n \pmod{p}\) ,则 \(A^2 + B^2 i^2 + 2ABi \equiv n \pmod{p}\) ,即 \(A^2 + B^2 (a^2 - n) - n \equiv -2ABi \pmod{p}\)

式子左边虚部为 \(0\) ,故右边虚部也为 \(0\) ,即 \(AB \equiv 0 \pmod{p}\)

假设 \(B \not = 0\) ,则 \(A = 0\) ,也就是说 \((Bi)^2 \equiv n \pmod{p}\) ,即 \(i^2 \equiv n B^{-2} \pmod{p}\)

由于 \(B^2\) 是个二次剩余,其逆元 \(B^{-2}\) 一定也是个二次剩余,乘上二次剩余 \(n\) 后仍为二次剩余,这与 \(i^2\) 是非二次剩余矛盾,故假设不成立,即 \(B = 0\)

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;

mt19937 myrand(time(0));
ll n, p, i2;

struct Node {
    ll a, b;
    
    inline Node(const ll _a = 0, const ll _b = 0) : a(_a), b(_b) {}
    
    inline Node operator * (const Node &rhs) const {
        return Node(((a * rhs.a % p + i2 * b % p * rhs.b % p) % p + p) % p, 
            ((a * rhs.b % p + b * rhs.a % p) % p + p) % p);
    }
};

inline Node mi(Node a, ll b) {
    Node res(1);
    
    for (; b; b >>= 1, a = a * a)
        if (b & 1)
            res = res * a;
    
    return res.a;
}

inline ll mi(ll a, ll b, ll p){
    ll res = 1;
    
    for (; b; b >>= 1, a = a * a % p)
        if (b & 1)
            res = res * a % p;
    
    return res;
}

inline ll Cipolla(ll n, ll p) {
    n %= p;
    
    if (mi(n, (p - 1) / 2, p) == p - 1)
        return -1;
    
    ll a;
    
    for (;;) {
        a = myrand() % p;
        i2 = ((a * a % p - n) % p + p) % p;
        
        if (mi(i2, (p - 1) / 2, p) == p - 1)
            break;
    }
    
    Node x(a, 1);
    return mi(x, (p + 1) / 2).a;
}

signed main() {
    int T;
    scanf("%d", &T);
    
    while (T--) {
        scanf("%lld%lld", &n, &p);
        
        if (!n) {
            puts("0");
            continue;
        }
        
        ll x1 = Cipolla(n, p), x2 = p - x1;
        
        if (x1 == -1)
            puts("Hola!");
        else {
            if (x1 == x2)
                printf("%lld\n", x1);
            else
                printf("%lld %lld\n", min(x1, x2), max(x1, x2));
        }
    }
    
    return 0;
}

posted @ 2025-06-10 13:41  wshcl  阅读(46)  评论(0)    收藏  举报