A square root of a number x is a number r such that r2 = x. A discrete square root of a non-negative integerx is a non-negative integer r such that r2 x mod N , 0r <N , where N is a specific positive integer and mod is the modulo operation.
It is well-known that any positive real number has exactly two square roots, but a non-negative integer may have more than two discrete square roots. For example, forN = 12 , 1 has four discrete square roots 1, 5, 7 and 11.
Your task is to find all discrete square roots of a given non-negative integerx. To make it easier, a known square root r of x is also given to you.
Input
The input consists of multiple test cases. Each test case contains exactly one line, which gives three integersx, N and r. (1x <N, 2N < 1, 000, 000, 000, 1r < N). It is guaranteed that r is a discrete square root ofx modulo N. The last test case is followed by a line containing three zeros.
Output
For each test case, print a line containing the test case number (beginning with 1) followed by a list of corresponding discrete square roots, in which all numbers are sorted increasingly..
Sample Input
1 12 1 4 15 2 0 0 0
Sample Output
Case 1: 1 5 7 11 Case 2: 2 7 8 13
给你一个满足0<=r<n且r^2=x(mod n)的r1,找出所有满足这个条件的的r。
设另一个解为r2。
r1^2+k1*n=x
r2^2+k2*n=x
因此r1^2-r2^2=(r1+r2)(r1-r2)=k3*n
设A*B=n
K1*A=r1+r2
K2*B=r1-r2
因此A*K1=2*r1 mod B
用模线性方程找出k1之后r2=ak1-r1,判断是否满足条件。
注意和一般的模线性方程有点不一样,因为最后是模n下的,不是模B下的,所以不只d个解,要找全N之内的所有解。
线性模方程的做法:在模n下,先用扩展gcd找到ax=b mod n的一个解x0,设e=x0+n,方程ax=b(mod n)的最小整数解x1=e mod(n/d),最大整数解x2=x1+(d-1)*(n/d)。
#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<algorithm>
#define eps 1e-9
#define MAXN 510
#define MAXM 110
#define MOD 100000007
typedef long long LL;
using namespace std;
LL X,N,R;
set<LL> s;
void extend_gcd(LL a,LL b,LL& d,LL& x,LL& y){
if(!b){
d=a;
x=1;
y=0;
}
else{
extend_gcd(b,a%b,d,y,x);
y-=a/b*x;
}
}
void mod_line_equation(LL a,LL b,LL n){
LL x,y,d;
extend_gcd(a,n,d,x,y);
if(b%d==0){
x=(x*b/d%(n/d)+n/d)%(n/d);
LL t=a*x-R,cir=a*n/d,ans=t;
while(ans<N){
if(ans>=0&&ans*ans%N==X%N) s.insert(ans);
ans+=cir;
}
}
}
int main(){
freopen("in.txt","r",stdin);
int cas=0;
while(scanf("%lld%lld%lld",&X,&N,&R)&&(X||N||R)){
s.clear();
LL sq=sqrt(N)+0.5;
for(LL i=1;i<=sq;i++) if(N%i==0){
mod_line_equation(i,2*R,N/i);
mod_line_equation(N/i,2*R,i);
}
printf("Case %d:",++cas);
set<LL>::iterator it;
for(it=s.begin();it!=s.end();it++) printf(" %lld",*it);
puts("");
}
return 0;
}