單變元模線性方程演算法及證明
阿新 • • 發佈:2019-02-14
題目
已知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;
}