Solution
先列出最简单的柿子:
[(X+mT) \% L=(Y+nT) \% L
]
下面推导过程:
[(X + mT) \% L = (Y + nT) \% L
]
[⇒ X + mT equiv Y + nT (\%L)
]
[⇒ (m-n)T equiv Y-X (\% L)
]
其中 (m-n), (Y-X) 已知,分别设为 (a), (c), 上面的柿子可以写成如下形式:
[aT + yL = c
]
如果用 (x) 表示 (T), (b) 表示 (L),这个柿子还可以变成更优美的形式:
[ax + by = c
]
[(a=m-n, b=L, c=Y-X)
]
这就变成线性同余方程的一般柿子了。
考虑用 exgcd 求出一组对于 (ax+by=gcd(a,b)) 的特解,记为 (x_0), (y_0)。显然:
[ax_0+by_0=gcd(a, b)
]
[⇒ ax_0 frac{c}{gcd(a,b)} +by_0 frac{c}{gcd(a,b)} = gcd(a,b) frac{c}{gcd(a,b)}
]
[⇒ a frac{x_0c}{gcd(a,b)} + b frac{y_0c}{gcd(a,b)} = c
]
于是我们对原方程求出了一组特解:
[x = frac{x_0c}{gcd(a,b)}, y = frac{y_0c}{gcd(a,b)}
]
考虑通解。设 (x, y) 是已求出的特解,则有:
[ax+by=a(x+bd)+b(y-ad)
]
要使 (bd, ac) 最小且为整数,(d) 的最小值为 (frac{1}{gcd(a,b)})。因此:
[x_{min}=x \% frac{b}{gcd(a,b)}
]
注意负数取模。
另外,如果计算前 (a) 是负数,就对 (a) 和 (c) 取相反数。
Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
long long X, Y, m, n, l, a, b, c, x, y, g;
long long gcd(long long x, long long y) { return y == 0 ? x : gcd(y, x % y); }
void exgcd(long long a, long long b)
{
if(b == 0)
{
x = 1, y = 0;
return ;
}
exgcd(b, a % b);
long long tx = x;
x = y, y = tx - (a / b) * y;
}
int main()
{
scanf("%lld%lld%lld%lld%lld", &X, &Y, &m, &n, &l);
a = m - n, b = l, c = Y - X, g = gcd(a, b);
if(a < 0) a = -a, c = -c;
g = gcd(a, b);
if(c % g != 0) { printf("Impossible"); return 0; }
exgcd(a, b);
printf("%lld", ((x * (c / g)) % (b / g) + (b / g)) % (b / g));
return 0;
}