UVa 1426 Discrete Square Roots (Extended Euclidean)

Question meaning: Given x, n, r, satisfy r 2 ≡ x mod(n) , find all rr that satisfy rr 2 ≡ x mod(n) within 0 ~ n  .

Analysis: Obviously, it will definitely not work directly, the complexity is too high.

 r 2  ≡ x mod (n) (1)

rr 2  ≡ x mod(n) (2)
is obtained by (2) - (1)

rr2 - r2 ≡ 0 mod (n)

(rr + r)*(rr - r) ≡ 0 mod (n),

can get

(rr + r)*(rr - r) = k * n。

Suppose n = a * b,

Then we can know that (rr + r) % a == 0 && (rr - r) % b == 0 || (rr + r) % b == 0 && (rr - r) % a == 0,

that is 

rr + r = k1 * a  (3)

rr - r = k2 * b   (4)

(3)-(4) get

k1 * a + k2 * b = 2 * r,

This is an equation, r is known, and then a and b can be obtained by enumerating the factors of n, so that the equation can be solved, and k1 can be solved in (3), and rr can be obtained.

It solves this problem, and this may produce duplicate solutions, so you can use set.

code show as below:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <set>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <cctype>
#include <cmath>
#include <stack>
#include <sstream>
#include <list>
#include <assert.h>
#include <bitset>
#include <numeric>
#define debug() puts("++++")
#define gcd(a, b) __gcd(a, b)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define fi first
#define se second
#define pb push_back
#define sqr(x) ((x)*(x))
#define ms(a,b) memset(a, b, sizeof a)
#define sz size()
#define be begin()
#define ed end()
#define pu push_up
#define pd push_down
#define cl clear()
#define lowbit(x) -x&x
//#define aLL 1,n,1
#define FOR(i,n,x)  for(int i = (x); i < (n); ++i)
#define freopenr freopen("in.in", "r", stdin)
#define freopenw freopen("out.out", "w", stdout)
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const LL LNF = 1e17;
const double inf = 1e20;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int maxn = 300 + 20;
const int maxm = 76543;
const int mod = 1e9 + 9;
const int dr[] = {-1, 1, 0, 0, 1, 1, -1, -1};
const int dc[] = {0, 0, 1, -1, 1, -1, 1, -1};
const char *de[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
int n, m;
const int my[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
inline bool is_in(int r, int c) {
  return r >= 0 && r < n && c >= 0 && c < m;
}
inline int readInt(){ int x;  scanf("%d", &x);  return x; }

void exgcd(int a, int b, LL &d, LL &x, LL &y){
  if(!b){ d = a;  x = 1; y = 0; }
  else{ exgcd(b, a%b, d, y, x); y -= (a/b) * x; }
}


int main(){
  int x, r, kase = 0;
  while(scanf("%d %d %d", &x, &n, &r) == 3 && x + n + r){
    vector<P> fact;
    int t = sqrt(n + 1.);
    for(int i = 1; i <= t; ++i)  if(n % i == 0)  fact.pb(P(i, n/i)), fact.pb(P(n/i, i));
    set<int> sets;
    sets.insert(r);
    LL k1, k2, d;
    for(int i = 0; i < fact.sz; ++i){
      int a = fact[i].fi;
      int b = fact[i].se;
      exgcd(a, b, d, k1, k2);
      if(2 * r % d)  continue;
      int bb = abs(b / d);
      LL K1 = k1 * 2LL * r / d;
      k1 = (K1 % bb + bb) % bb;
      k2 = k1;
      while(1){
        LL rr = k1 * a - r;
        if(rr >= 0){
          if(rr >= n)  break;
          sets.insert(rr);
        }
        k1 += bb;
      }
      while(1){
        LL rr = k2 * a - r;
        if(rr <= n){
          if(rr < 0)  break;
          sets.insert(rr);
        }
        k2 -= bb;
      }
    }
    printf("Case %d:", ++kase);
    for(auto &it: sets)  printf(" %d", it);
    printf("\n");
  }
  return 0;
}

  

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324779070&siteId=291194637