UVALive 4270 Discrete Square Roots

题目描述:

  在已知一个离散平方根的情况下,按照从小到大的顺序输出其他所有的离散平方根。

  在模n意义下,非负整数x的离散平方根是满足0<=r<n且r2=x(mod n)的整数r。

解题思路:

  假设要求的一个离散平方根为r1,则有:

    r2=x(mod n)

    r12=x(mod n)

  两式相减可得:

    r2-r12=0(mod n)

  即:

    r2-r12=kn

  令:

    a*b=n

  则有:

    r-r1=0(mod a)

    r+r1=0(mod b)

  即:

    r-r1=k1a

    r+r1=k2b

  两式相加可得:

    k1a+k2b=2r

  

  据此,枚举n的所有约数,得到所有可能的a和b。

  再利用扩展欧几里得算法解出所有的k2,代入r-r1=k1a即可得到r1

 

代码在这:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef  long long ll;
 4 
 5 set<ll> ans;
 6  ll x,n,r;
 7 
 8 //扩展欧几里得算法
 9 void gcd(ll a,ll b,ll& d,ll& x,ll& y)
10 {
11     if(b==0)
12     {
13         d=a;
14         x=1;
15         y=0;
16     }
17     else
18     {
19         gcd(b,a%b,d,y,x);
20         y-=x*(a/b);
21     }
22 }
23 
24 void solve(ll a,ll b)
25 {
26     ll k1,k2,d;
27     gcd(a,b,d,k1,k2);
28 
29     if(2*r%d)
30         return;
31 
32     k2*=(2*r/d);
33 
34     ll aa=a/d;
35     k2%=aa;//k2是所有形如k2+k*aa的整数,最小的k2对应最小的r1
36 
37     ll r1=k2*b-r;
38     while(r1<n)
39     {
40         if(r1>=0&&r1*r1%n==x)
41             ans.insert(r1);
42 
43         r1+=aa*b;
44     }
45 }
46 
47 int main()
48 {
49     int ca=0;
50     while(~scanf("%lld%lld%lld",&x,&n,&r))
51     {
52         if(x==0&&n==0&&r==0)
53             break;
54 
55         ans.clear();
56 
57         for(ll i=1;i*i<=n;i++)
58             if(n%i==0)
59             {
60                  solve(i,n/i);
61                  solve(n/i,i);
62             }
63 
64 
65         printf("Case %d: %lld",++ca,*ans.begin());
66         for(set<ll>::iterator it=ans.begin();it!=ans.end();it++)
67             if(it!=ans.begin())
68             printf(" %lld",*it);
69         printf("\n");
70     }
71     return 0;
72 }

 

posted @ 2017-03-18 14:58  From_00  阅读(234)  评论(0编辑  收藏  举报