【初等数论】如何用程序求解单变元模线性方程?

如何求解单变元模线性方程?
单变元模线性方程即 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 
#include
#include
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;
}

你可能感兴趣的:(ACM,数论,算法)