uva1426 - Discrete Square Roots 模线性方程

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 $ \equiv$x mod N , 0$ \le$r <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. (1$ \le$x <N, 2$ \le$N < 1, 000, 000, 000, 1$ \le$r < 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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值