Timus Online Judge传送门
Vjudge传送门
Description
The number x is called a square root of a modulo n (root( a, n)) if x * x = a (mod n). Write the program to find the square root of number a by given modulo n.
Input
One number K in the first line is an amount of tests ( K ≤ 100000). Each next line represents separate test, which contains integers a and n (1 ≤ a, n ≤ 32767, n is prime, a and n are relatively prime).
Output
For each input test the program must evaluate all possible values root( a, n) in the range from 1 to n − 1 and output them in increasing order in one separate line using spaces. If there is no square root for current test, the program must print in separate line: ‘No root’.
Example
Input
5
4 17
3 7
2 7
14 31
10007 20011
Output
2 15
No root
3 4
13 18
5382 14629
解题分析
二次剩余模板题, 这里用 算法做, 只讨论奇质数的情况。
首先我们有欧拉准则:
证明:
-
充分性:
-
必要性:
设 为 的原根, 。
那么有
就有 , 即 为偶数。
那么 有一组解为 。
对于一组 , 我们已经可以用欧拉准则判定是否有解(特判2)。
现在我们先需要找到一组满足 , 且w为非二次剩余的 和 。这个也很好做, 只需要瞎 b, 然后判 是否在 意义下等于 就好了。
不妨扩域, 设 , 将一个数表示为 , 类似于复数。
定义代数系统
满足:
那么可以发现,
实际上是一个环, 满足结合律、交换律。
然后又有一个神仙结论: 。
证明(以下都在模
意义下讨论):
发现
当且仅当
或
的时候后不被
整除, 那么有
得证。
代码如下:
#include <cstdio>
#include <cmath>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define ll long long
struct QF {ll re, im, w;};
struct INFO {ll b, w;};
IN QF operator * (const QF &x, const QF &y) {return {x.re * y.re + x.w * y.im * x.im, x.im * y.re + y.im * x.re, x.w};}
IN QF operator + (const QF &x, const QF &y) {return {x.re + y.re, x.im + y.im, x.w};}
IN QF fpow(QF x, R ll tim, R ll mod)
{
QF ret = {1, 0, x.w};
W (tim)
{
if (tim & 1) ret = ret * x;
x = x * x, tim >>= 1;
ret.re %= mod, ret.im %= mod;
x.re %= mod, x.im %= mod;
}
return ret;
}
IN ll fpow(R ll base, R ll tim, R ll mod)
{
ll ret = 1;
W (tim)
{
if (tim & 1) ret = ret * base % mod;
base = base * base % mod, tim >>= 1;
}
return ret;
}
IN bool check(R int val, R int n) {return fpow(val, (n - 1) / 2, n) == 1;}
IN INFO find(R int a, R int n)
{
ll b;
W (233)
{
b = rand() % n;
if (!check((b * b % n - a + n) % n, n)) return {b, (b * b % n - a + n) % n};
}
}
int main(void)
{
using namespace std;
int T, n, a; INFO dat; ll res;
ios_base::sync_with_stdio(false);
cin >> T;
W (T--)
{
cin >> a >> n; a %= n;
if (n == 2) {cout << "1" << endl; continue;}
if (!check(a, n)) {cout << "No root" << endl; continue;}
dat = find(a, n);
res = fpow({dat.b, 1, dat.w} ,((n + 1) >> 1), n).re;
if (res * 2 == n) cout << res << endl;
else
{
if (res * 2 > n) res = n - res;
cout << res << " " << n - res << endl;
}
}
}