Link to the question: Ultraviolet A 1426-discrete square roots
Returns X, N, R, and returns all satisfied R, so that R2 returns X % N, and R is a solution.
Solution:
- R2? R2 = K? N
- (R? R) (R + R) = K? N
- => AA = (R + r), BB = (r? R), A, and B are the factors of N.
So if we enumerate a and B, r = r? AA = BB? R
- AA + BB = 2? R
Expand the Euclidean solution and free all satisfied items into the set to automatically remove duplicates.
#include <cstdio>#include <cstring>#include <cmath>#include <set>#include <algorithm>using namespace std;typedef long long ll;ll X, N, R;set<ll> ans;void exgcd (ll a, ll b, ll& d, ll& x, ll& y) { if (b == 0) { d = a; x = 1; y = 0; } else { exgcd (b, a%b, d, y, x); y -= (a/b) * x; }}void solve (ll A, ll B, ll C) { ll d, x, y; exgcd(A, B, d, x, y); if (C % d) return; x = x * C / d; x = (x % (B/d) + (B/d))%(B/d); ll s = x * A - C / 2; ll k = A * B / d; for (ll i = s; i < N; i += k) if (i >= 0) ans.insert(i);}int main () { int cas = 1; while (scanf("%lld%lld%lld", &X, &N, &R) == 3 && X + N + R) { ans.clear(); ll m = sqrt(N+0.5); for (ll i = 1; i <= m; i++) { if (N%i) continue; solve(i, N/i, 2*R); solve(N/i, i, 2*R); } printf("Case %d:", cas++); for (set<ll>::iterator i = ans.begin(); i != ans.end(); i++) printf(" %lld", *i); printf("\n"); } return 0;}