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 }