【模板】二次剩餘

傳送門html

參考c++

二次剩餘

勒讓德符號(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)ui

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;
	}
}
相關文章
相關標籤/搜索