题目
已知a,b,n,求x,使得ax=b(mod n).
算法说明
令d=gcd(a,n),如果d|b,则存在d个解。否则无解。
用扩展欧几里得算法求出 ax+ny=d 的一组解(x0,y0).x0即为ax=b(mod n)的一个解。d个解满足x=x0+i*n/d,i取值范围是[0,d-1].
推导过程
由同余方程的定义,可知ax-ny=b.
将b拆分为gcd(a,n)*t.
若gcd(a,n)不能整除b,因为ax0+ny0=gcd(a,n).等式左边有因子gcd(a,n),而等式右边没有,所以此时是无解的。
设x0,y0满足ax0+ny0=gcd(a,n).
等式两边同乘以t,得
a(x0*t)-n(-y0*t)=gcd(a,n)*t.
即x0*t为ax=b(mod n)的一个解。
通解证明:
设(x1,y1)和(x2,y2)是ax-ny=b的解。
ax1 - ny1 = b; …(1)
ax2 - ny2 = b; …(2)
(2) - (1),得:
a(x2 - x1) = n(y2 - y1)
等式两边同时除以d,d=gcd(a,n).得:
a/d * (x2 - x1) = n/d * (y2 - y1).
因为 a/d 和 n/d互质了,所以(x2 - x1)一定是 n/d 的倍数,即
x2 - x1 = n/d * i.
i的最大取值为d - 1.因为如果 i = d 的话,x2 - x1 = n.
ax2 = b(mod n).即
a(x1 + n) = b(mod n),
ax1 + a*n = b(mod n).
x2和x1是模n下的同一个解。所以i的取值范围是[0,d-1].
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll ex_gcd(ll a,ll b,ll &x,ll &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
else
{
ll r=ex_gcd(b,a%b,x,y);
ll t=x;
x=y;
y=t-y*a/b;
return r;
}
}
vector<ll> cm(ll a,ll b,ll n)
{
ll x,y;
vector<ll> ans;
ans.clear();
ll d=ex_gcd(a,n,x,y);
if(b%d==0)
{
ans.push_back(x*(b/d)%n);
for(ll i=1; i<d; i++)
ans.push_back((ans[0]+i*n/d)%n);
return ans;
}
}
int main()
{
ll a,b,n;
while(cin>>a>>b>>n)
{
vector<ll> ans=cm(a,b,n);
for(ll i=0;i<ans.size();i++)
cout<<ans[i]<<endl;
}
return 0;
}