wikipedia上的解释和证明:http://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm

The Tonelli–Shanks algorithm (referred to by Shanks as the RESSOL algorithm) is used within modular arithmetic to solve a congruence of the form

Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root)

where n is a quadratic residue (mod p), and p is an odd prime.

Tonelli–Shanks cannot be used for composite moduli; finding square roots modulo composite numbers is a computational problem equivalent to integer factorization.[1]

An equivalent, but slightly more redundant version of this algorithm was developed by Alberto Tonelli in 1891. The version discussed here was developed independently by Daniel Shanksin 1973, who explained:

"My tardiness in learning of these historical references was because I had lent Volume 1 of Dickson's History to a friend and it was never returned."[2]


(Note: All Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) are taken to mean Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root), unless indicated otherwise).[edit]
The algorithm

Inputsp, an odd prime. n, an integer which is a quadratic residue (mod p), meaning that the Legendre symbol Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root).

OutputsR, an integer satisfying Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root).

  1. Factor out powers of 2 from p − 1, defining Q and S as: Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) with Q odd. Note that if Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root)i.e. Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root), then solutions are given directly by Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root).
  2. Select a z such that the Legendre symbol Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) (that is, z should be a quadratic non-residue modulo p), and set Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root).
  3. Let Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root)
  4. Loop:
    1. If Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root), return R.
    2. Otherwise, find the lowest iTonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root), such that Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root)e.g. via repeated squaring.
    3. Let Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root), and set Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) and Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root).

Once you have solved the congruence with R the second solution is p − R.

Example

Solving the congruence Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root). It is clear that Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) is odd, and since Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root), 10 is a quadratic residue (by Euler's criterion).

  • Step 1: Observe Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) so Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root)Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root).
  • Step 2: Take Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) as the quadratic nonresidue (2 is a quadratic nonresidue since Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) (again, Euler's criterion)). Set Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root)
  • Step 3: Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root)
  • Step 4: Now we start the loop: Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) so Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root)i.e. Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root)
    • Let Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root), so Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root).
    • Set Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root). Set Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root), and Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root)
    • We restart the loop, and since Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) we are done, returning Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root)

Indeed, observe that Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) and naturally also Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root). So the algorithm yields two solutions to our congruence.

Proof

First write Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root). Now write Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) and Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root), observing that Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root). This latter congruence will be true after every iteration of the algorithm's main loop. If at any point, Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) then Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) and the algorithm terminates with Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root).

If Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root), then consider Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root), a quadratic non-residue of Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root). Let Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root). Then Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) and Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root), which shows that the order of Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) is Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root).

Similarly we have Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root), so the order of Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) divides Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root). Suppose the order of Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) is Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root). Since Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) is a square modulo Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root)Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) is also a square, and hence Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root).

Now we set Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) and with this Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root)Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) and Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root). As before, Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root)holds; however with this construction both Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) and Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) have order Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root). This implies that Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) has order Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) with Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root).

If Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) then Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root), and the algorithm stops, returning Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root). Else, we restart the loop with analogous definitions of Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root)Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root)Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root)and Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) until we arrive at an Tonelli–Shanks Algorithm 二次剩余系解法 (Ural 1132. Square Root) that equals 0. Since the sequence of S is strictly decreasing the algorithm terminates.

 
 
算法的大体过程已经说的很清楚,然后模拟那个过程就可以了,不过对于Ural上的这个题,要对n = 2特判一下。详见代码:
 
 
//#pragma comment(linker,"/STACK:327680000,327680000")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))
#define REP(i, n)       for((i) = 0; (i) < (n); ++(i))
#define FOR(i, l, h)    for((i) = (l); (i) <= (h); ++(i))
#define FORD(i, h, l)   for((i) = (h); (i) >= (l); --(i))
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d\n", x)
#define Read()  freopen("data.in", "r", stdin)
#define Write() freopen("data.out", "w", stdout);

typedef long long LL;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double inf = ~0u>>2;


using namespace std;

LL MOD;

LL mod_exp(LL a, LL b) {
    LL res = 1;
    while(b > 0) {
        if(b&1)    res = (res*a)%MOD;
        a = (a*a)%MOD;
        b >>= 1;
    }
    return res;
}

LL solve(LL n, LL p) {
    int Q = p - 1, S = 0;
    while(Q%2 == 0) {
        Q >>= 1;
        S++;
    }
    if(S == 1) {return mod_exp(n, (p + 1)/4);}
    int z;
    while(1) {
        z = 1 + rand()%(p - 1);
        if(mod_exp(z, (p - 1)/2) != 1)   break;
    }
    LL c = mod_exp(z, Q);
    LL R = mod_exp(n, (Q + 1)/2);
    LL t = mod_exp(n, Q);
    LL M = S, b, i;
    while(1) {
        if(t%p == 1)  break;
        for(i = 1; i < M; ++i) {
            if(mod_exp(t, 1<<i) == 1)    break;
        }
        b = mod_exp(c, 1<<(M-i-1));
        R = (R*b)%p;
        t = (t*b*b)%p;
        c = (b*b)%p;
        M = i;
    }
    return (R%p + p)%p;
}

int main() {
    //Read();

    int T, a, n, i;
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d", &a, &n);
        if(n == 2) {    //***
            if(a%n == 1)    printf("1\n");
            else    puts("No root");
            continue;
        }
        MOD = n;
        if(mod_exp(a, (n-1)/2) != 1)    {puts("No root"); continue; }

        i = solve(a, n);
        if(i == n - i)  printf("%d\n", i);
        else    printf("%d %d\n", min(i, n - i), max(i, n - i));
    }
    return 0;
}

 

 
 POJ 1808 勒让德符号(Legendre symbol)判定
 
View Code
//#pragma comment(linker,"/STACK:327680000,327680000")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))
#define REP(i, n)       for((i) = 0; (i) < (n); ++(i))
#define FOR(i, l, h)    for((i) = (l); (i) <= (h); ++(i))
#define FORD(i, h, l)   for((i) = (h); (i) >= (l); --(i))
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d\n", x)
#define Read()  freopen("data.in", "r", stdin)
#define Write() freopen("data.out", "w", stdout);

typedef long long LL;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double inf = ~0u>>2;


using namespace std;

LL MOD;

LL mod_exp(LL a, LL b) {
    LL res = 1;
    while(b > 0) {
        if(b&1)    res = (res*a)%MOD;
        a = (a*a)%MOD;
        b >>= 1;
    }
    return res;
}

int main() {
    //Read();

    LL a, p;
    int T, cas = 0;
    scanf("%d", &T);
    while(T--) {
        scanf("%lld%lld", &a, &p);
        MOD = p;
        printf("Scenario #%d:\n", ++cas);
        if(mod_exp((a%p+p)%p, (p - 1)/2) == 1)  puts("1");    //注意a有可能是负数
        else    puts("-1");
        cout << endl;
    }
}

 

 
 
 
 
 

相关文章:

  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-09-09
  • 2022-01-30
  • 2021-08-13
  • 2021-07-31
  • 2021-09-20
  • 2021-11-27
相关资源
相似解决方案