传送门

参考

二次剩余

勒让德符号(Wikipedia)

\[{\displaystyle \left({\frac {a}{p}}\right)={\begin{cases}1&{\text{if }}a{\text{ is a quadratic residue modulo }}p{\text{ and }}a\not \equiv 0{\pmod {p}},\\-1&{\text{if }}a{\text{ is a non-quadratic residue modulo }}p,\\0&{\text{if }}a\equiv 0{\pmod {p}}.\end{cases}}}\]

定理0

在模\(p\)意义下,分别有\(\frac{p-1}{2}\)二次剩余非二次剩余

定理1

\[\left({\frac {a}{p}}\right) \equiv a^{\frac{p-1}2}\pmod p\]

(仿定理0)

Cipolla 算法

  1. 假设要求\(x^2\equiv n\pmod p\),随机一个数\(a\),使得\(a^2-n\)非二次剩余
  2. \(w=\sqrt{a^2-n}\),构造一个所有数都可以表示成\(a+bw\)\(\mathbb F_{p^2}\)(?)。
  3. 则一个可行的\(x\equiv(a+w)^{\frac{p+1}2}\pmod p\)。快速幂即可求。

定理2

\[w^p=-w\pmod p\]

定理3

\[\forall x, y\in \mathbb F_{p^2}:(x+y)^p\equiv x^p+y^p\pmod p\]

定理4

\[(a+w)^{p+1}\equiv n\pmod p\]

代码

#include <bits/stdc++.h>
#define int ll
using namespace std;

typedef long long ll;
int t, n, p, a, w;

ostream& operator <<(ostream &, struct p2);

struct p2{
    ll a, b;
    p2 operator *(const p2 &q) {
        return (p2){(a*q.a+b*q.b%p*w)%p, (a*q.b+b*q.a)%p};
    }
    p2 operator %(const int p) {
        return (p2){a%p, b%p};
    }
};

template<typename T>
T qpow(T a, int x, T e) {
    return (x?(qpow(a*a%p, x/2, e)*(x&1?a:e)):e)%p;
}

signed main() {
    cin >> t;
    while (t--) {
        cin >> n >> p;
        int tmp = qpow<ll>(n, (p-1)/2, 1);
        if (tmp == 0) {
            cout << 0 << endl;
            continue;
        } else if (tmp == p-1) {
            cout << "Hola!\n";
            continue;
        }
        do {
            a = rand()%p;
        } while (qpow<ll>(w=((ll)a*a+p-n)%p, (p-1)/2, 1) != p-1);
        p2 x = qpow((p2){a/*注意这里的a……调了半天*/, 1}, (p+1)/2, (p2){1,0});
        cout << min(p-x.a, x.a) << ' ' << max(p-x.a, x.a) << endl;
    }
}
01-04 02:51