LA 4270 Discrete Square Roots
题目大意:
在模n的意义下,非负整数x的离散平方根是满足
0≤r<n
的整数,所以一个x可能会有多个离散平方根.
输入x,n,r(
1≤x<n,2≤n≤109,1≤r≤n
),输出数据编号和所有离散平方根,从小到大排序.
题目分析:
(又是一道扩欧的题,orz……)
已知
r2≡x(mod n)
,则有
r2−x=k1n
,设
r′2−x=k2n
所以
r′2−r2=k3n
,则有
(r′+r)(r′−r)=k3n
设 a∗b=n ,所以
(r′+r)(r′−r)=k3ab
r′+r≡a(mod n),r′−r≡b(mod n)
(一开始的时候推导到这里就推不下去了,orz……)
r′+r=ax,r′−r=by
(r′+r)+(r′−r)=ax+by
ax+by=2r′
得到一个直线模方程
ax+by=2r′
,通过扩欧求解.
因为
a∗b=n
,所以枚举
n
<script type="math/tex" id="MathJax-Element-282">n</script>的因子求解(详见代码).
代码:
#include<cmath>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
typedef long long ll;
void exgcd(ll a,ll b,ll& g,ll& x,ll& y)
{
if(!b) g=a,x=1,y=0;
else exgcd(b,a%b,g,y,x),y-=x*(a/b);
}
ll x,n,r;
set<ll>ans;
void solve(ll a,ll b,ll c)//c=2r
{
ll g,x,y;
exgcd(a,b,g,x,y);//ax+by=gcd(a,c)
if(c%g) return ;
x*=c/g;//ax+by=c的一组解x0
b/=g;//b'
x=(x%b+b)%b;//x的非负整数解,x=x0+kb'
ll r=a*x-c/2;//r的一组解,可能为负
ll p=a*b;//p=a*b' 因为x=x0+k*b',r=ax+r'=k*a*b'+r'
while(r<n) {
if(r>=0) ans.insert(r);
r+=p;
}
}
int main()
{
int kase=0;
while(scanf("%lld%lld%lld",&x,&n,&r)==3&&n) {
ans.clear();
ll m=sqrt(n);
for(ll i=1;i<=m;i++) if(n%i==0)
solve(i,n/i,2*r),solve(n/i,i,2*r);
printf("Case %d:",++kase);
for(set<ll>::iterator it=ans.begin();it!=ans.end();it++)
printf(" %lld",*it);
printf("\n");
}
return 0;
}