求解范围 [0, N-1] 中 x 值的线性同余 Ax = B (mod N)
给定三个正整数A 、 B和N ,它们表示AX=B (mod N) 形式的线性同余,任务是打印X (mod N)的所有可能值,即 在满足该方程的[0, N-1]范围内。如果没有解决方案,打印 -1。
例子:
Input: A=15, B=9, N=18
Output: 15, 3, 9
Explanation: The values of X satisfying the condition AX=B (mod N) are {3, 9, 15}.
(15*15)%18 = 225%18=9
(3*15)%18 = 45%18=9
(9*15)%18 = 135%18=9
Input: A=9, B=21, N=30
Output: 9, 19, 20
方法:这个想法基于以下观察:
- 当且仅当B可被GCD (A, N)整除,即B%GCD(A, N)=0时,才存在解决方案。
- X (mod N)的解数是GCD(A, N) 。
证明:
- Given, AX=B (mod N)
⇒ there exist a number Y such that AX=B+NY
AX-NY=B — (1)
This is a linear Diophantine equation, and is solvable if and only if GCD(A, N) divides B. - Now, using the Extended Euclidean Algorithm, u and v can be found such that Au+Nv=GCD(A, N)=d(say)
⇒ Au+Nv=d
⇒ Au=d (mod N) — (2) - Assuming B%d=0, so that solution of Equation 1 exists,
Multiplying both sides of Equation 2 by B/d, (possible since B/d is an integer),
Au*(B/d)=d*(B/d) (mod N) or A*(u*B/d)=B (mod N).
Thus, u*B/d is a solution of Equation 1. - Let X0 be u*B/d.
Thus, the d solutions of Equation 1 will be X0, X0+(N/d), X0+2*(N/d), …, X0+(d-1)*(N/d)
请按照以下步骤解决问题:
- 使用扩展欧几里得算法将变量d初始化为GCD(A, N)以及u 。
- 如果B不能被d整除,则打印 -1 作为结果。
- 否则使用变量i在[0, d-1]范围内迭代,并在每次迭代中打印u*(B/d)+i*(N/d)的值。
下面是上述方法的实现:
C++
// C++ program for the above approach
#include
using namespace std;
// Function to stores the values of x and y
// and find the value of gcd(a, b)
long long ExtendedEuclidAlgo(
long long a, long long b,
long long& x, long long& y)
{
// Base Case
if (b == 0) {
x = 1;
y = 0;
return a;
}
else {
// Store the result of recursive call
long long x1, y1;
long long gcd
= ExtendedEuclidAlgo(b, a % b, x1, y1);
// Update x and y using results of
// recursive call
x = y1;
y = x1 - floor(a / b) * y1;
return gcd;
}
}
// Function to give the distinct
// solutions of ax = b (mod n)
void linearCongruence(long long A,
long long B,
long long N)
{
A = A % N;
B = B % N;
long long u = 0, v = 0;
// Function Call to find
// the value of d and u
long long d = ExtendedEuclidAlgo(A, N, u, v);
// No solution exists
if (B % d != 0) {
cout << -1 << endl;
return;
}
// Else, initialize the value of x0
long long x0 = (u * (B / d)) % N;
if (x0 < 0)
x0 += N;
// Print all the answers
for (long long i = 0; i <= d - 1; i++)
cout << (x0 + i * (N / d)) % N << " ";
}
// Driver Code
int main()
{
// Input
long long A = 15;
long long B = 9;
long long N = 18;
// Function Call
linearCongruence(A, B, N);
return 0;
}
Java
// Java program for the above approach
import java.io.*;
class GFG{
// Function to stores the values of x and y
// and find the value of gcd(a, b)
public static long[] ExtendedEuclidAlgo(long a,
long b)
{
// Base Case
if (a == 0)
{
return new long[]{b, 0, 1};
}
else
{
// Store the result of recursive call
long x1 = 1, y1 = 1;
long gcdy[] = ExtendedEuclidAlgo(b % a, a);
long gcd = gcdy[0];
x1 = gcdy[1];
y1 = gcdy[2];
// Update x and y using results of
// recursive call
long y = x1;
long x = y1 - (long)Math.floor(b / a) * x1;
return new long[] {gcd, x, y};
}
}
// Function to give the distinct
// solutions of ax = b (mod n)
public static void linearCongruence(long A,
long B,
long N)
{
A = A % N;
B = B % N;
long u = 0, v = 0;
// Function Call to find
// the value of d and u
long person[] = ExtendedEuclidAlgo(A, N);
long d = person[0];
u = person[1];
v = person[2];
// No solution exists
if (B % d != 0)
{
System.out.println(-1);
return;
}
// Else, initialize the value of x0
long x0 = (u * (B / d)) % N;
if (x0 < 0)
x0 += N;
// Print all the answers
for(long i = 0; i <= d - 1; i++)
{
long an = (x0 + i * (N / d)) % N;
System.out.print(an + " ");
}
}
// Driver Code
public static void main(String[] args)
{
// Input
long A = 15;
long B = 9;
long N = 18;
// Function Call
linearCongruence(A, B, N);
}
}
// This code is contributed by Shubhamsingh10
Python3
# Python3 program for the above approach
# Function to stores the values of x and y
# and find the value of gcd(a, b)
def ExtendedEuclidAlgo(a, b):
# Base Case
if a == 0 :
return b, 0, 1
gcd, x1, y1 = ExtendedEuclidAlgo(b % a, a)
# Update x and y using results of recursive
# call
x = y1 - (b // a) * x1
y = x1
return gcd, x, y
# Function to give the distinct
# solutions of ax = b (mod n)
def linearCongruence(A, B, N):
A = A % N
B = B % N
u = 0
v = 0
# Function Call to find
# the value of d and u
d, u, v = ExtendedEuclidAlgo(A, N)
# No solution exists
if (B % d != 0):
print(-1)
return
# Else, initialize the value of x0
x0 = (u * (B // d)) % N
if (x0 < 0):
x0 += N
# Pr all the answers
for i in range(d):
print((x0 + i * (N // d)) % N, end = " ")
# Driver Code
# Input
A = 15
B = 9
N = 18
# Function Call
linearCongruence(A, B, N)
# This code is contributed by SHUBHAMSINGH10
C#
// C# program for the above approach
using System;
class GFG{
// Function to stores the values of x and y
// and find the value of gcd(a, b)
public static long[] ExtendedEuclidAlgo(long a,
long b)
{
// Base Case
if (a == 0)
{
return new long[]{b, 0, 1};
}
else
{
// Store the result of recursive call
long x1 = 1, y1 = 1;
long[] gcdy = ExtendedEuclidAlgo(b % a, a);
long gcd = gcdy[0];
x1 = gcdy[1];
y1 = gcdy[2];
// Update x and y using results of
// recursive call
long y = x1;
long x = y1 - (long)(b / a) * x1;
return new long[] {gcd, x, y};
}
}
// Function to give the distinct
// solutions of ax = b (mod n)
public static void linearCongruence(long A,
long B,
long N)
{
A = A % N;
B = B % N;
long u = 0, v = 0;
// Function Call to find
// the value of d and u
long []person = ExtendedEuclidAlgo(A, N);
long d = person[0];
u = person[1];
v = person[2];
// No solution exists
if (B % d != 0)
{
Console.WriteLine(-1);
return;
}
// Else, initialize the value of x0
long x0 = (u * (B / d)) % N;
if (x0 < 0)
x0 += N;
// Print all the answers
for(long i = 0; i <= d - 1; i++)
{
long an = (x0 + i * (N / d)) % N;
Console.Write(an + " ");
}
}
// Driver Code
static public void Main (){
// Input
long A = 15;
long B = 9;
long N = 18;
// Function Call
linearCongruence(A, B, N);
}
}
// This code is contributed by Shubhamsingh10
Javascript
输出
15 3 9
时间复杂度: O(log(min(A, N))
辅助空间: O(1)