如何求解单变元模线性方程?
单变元模线性方程即 a*x ≡ b Mod C
首先需要掌握 “拓展欧几里得” 的知识,这里只介绍概念,不加求证
- 拓展欧几里得
已知 a , b
求 ax + by = gcd(a,b)
以下函数求解出 x 和 y,并返回 gcd(a,b) 的值
typedef long long ll;
ll exgcd(ll a,ll b,ll& x,ll& y){
if(b){
ll r = exgcd(b,a%b,y,x);
y-=(a/b)*x;
return r;
}
x = 1;
y = 0;
return a;
}
-
gcd(a,b) = 1,求解 a*x ≡1 Mod b
原式可化为: a*x = b*k +1
则:
a*x - b*k = 1 = gcd(a,b)
设y = -k
则:
a*x + b*y = gcd(a,b)
利用前面的拓展欧几里得算法可求得x -
终极一步,求解a*x ≡c Mod b
原式即a*x = k*b + c …①设d = gcd(a,b)
设置a = m*d,b = n*d
则结合①有 m*d*x = k*n*d + c
化简得 (m*x-k*n)d = c
因为(m*x-k*n)是整数,所以c/d == 0必须为真,否则原式无解当d==1时,有:
a*x ≡c*1 Mod b…②
exgcd(a,b,s,t)得到 a*s≡1 Mod b③
c*a*s ≡ c Mod b…④
所以ans1 = (c*s Mod b + b)Mod b为此式的最小正解
接下来有一系列解:ans1 + b*k都为该方程的解当d!=1时
参考 ① ,令其整体除以d
求解a/d *x ≡c/d Mod b/d即可,此时按照d==1的算法进行求解code
#include <iostream>
#include<vector>
#include<stdio.h>
using namespace std;
typedef long long ll;
ll exgcd(ll a,ll b,ll& x,ll& y){
if(b){
ll r = exgcd(b,a%b,y,x);
y-=(a/b)*x;
return r;
}
x = 1;
y = 0;
return a;
}
输出所有[0,n)中满足a\*x ≡c Mod b的解
vector<ll> line_mod_equation(ll a,ll b,ll n){
vector<ll> ans;
ans.clear();
ll x,y;
ll d = exgcd(a,n,x,y);
if(b%d == 0){
x = (x%n+n)%n;
ans.push_back(x*(b/d)%(n/d));
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(scanf("%lld %lld %lld",&a,&b,&n)){
if(n==0)break;
vector<ll> tmp = line_mod_equation(a,b,n);
for(int i = 0;i<tmp.size();++i){
printf("%lld ",tmp[i]);
}
printf("\n");
}
return 0;
}