这道题是Extended Euclidean Algorithm的应用。可以看
链接1(extended euclidean algorithm):http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
链接2(Bezout's Identity):http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity
这里的代码是按照wikipedia上链接1的描述写的。
首先假设当两只青蛙相遇时,都跳了K步(根据题意,它们跳得步数是一样的),并且第一只青蛙比第二只青蛙多跳了c圈(c可以为负数),这样,我们有:
x + Km - (y + Kn) = cL ,即:(x - y) + K(m - n) = cL,亦即:
K(n - m) + cL = (x - y) (以下称作原方程)
这样就转化为了一个可以应用Extended Euclidean Algorithm的问题。
Extended Euclidean Algorithm可以求出ax + by = gcd(a, b)的一个整数解(x0, y0)。然后根据链接2,我们知道这个方程的所有整数解为(x, y) = (x0 + kb/g, y - ka/g)。(这点比较好验证,带进去后面部分就都消掉了)。其中k是任意整数,g=gcd(a,b).
我们让a = n - m, b = L,那么我们可以根据上述extend euclidean algorithm得到一组解(x0, y0)。这个算法还可以附带得到g = gcd(a, b)。(所以不用单独跑gcd算法)。
很容易看出,既然左边能被g整除,那么右边的(x-y)也必须能够被g整除,否则原方程无解。
我们将原方程右边记做R,即R = x - y。
否则,我们可以得到这个方程的所有解: (x, y) = (R / g * x0 + kb/g, R/g * y0 + kb/g)。
按照问题,我们只关心第一项,即K = R / g * x0 + kb/g。我们要求的是这样一组K中最小的非负整数。
做法是先让K=0,求出k(这样的整数k不一定存在,但这样我们就可以求出使得K最接近0的k),然后求K。
k = (- R/g *x0) / (b/g)
然后K = R / g * x0 + (- R/g *x0) / (b/g) * b/ g。
注:上述公式中都是整数运算。
我们用P = R/g, Q = b / g,x0 = mQ + r带入上述简化表达式,有:
K = P * (mQ + r) - P (mQ + r) / Q * Q = P*(mQ + r) - P m Q = P*r = P * (x0 % Q) = (P*x0) % Q。
即K是P*x0对Q的余数。
剩下的值得注意的就是让Q为正数就好了(可以直接取Q的绝对值,因为这时相当于k的绝对值变了)。
程序如下:
1061 | Accepted | 216K | 0MS | C++ | 1906B |
/* ID: thestor1 LANG: C++ TASK: poj1061 */ #include <iostream> #include <fstream> #include <cmath> #include <cstdio> #include <cstring> #include <limits> #include <string> #include <vector> #include <list> #include <set> #include <map> #include <queue> #include <stack> #include <algorithm> #include <cassert> using namespace std; void extend_gcd(long long a, long long b, long long &g, long long &x0, long long &y0) { long long r0 = a, r1 = b, s0 = 1, s1 = 0, t0 = 0, t1 = 1; long long q2, r2, s2, t2; while (r1 != 0) { q2 = r0 / r1; r2 = r0 - r1 * q2; // r0 % r1 s2 = s0 - s1 * q2; t2 = t0 - t1 * q2; r0 = r1, r1 = r2; s0 = s1, s1 = s2; t0 = t1, t1 = t2; } // cout << a << " * " << s0 << " + " << b << " * " << t0 << " == " << r0 << "(GCD(" << a << ", " << b << "))" << endl; g = r0; x0 = s0; y0 = t0; } int main() { long long x, y, m, n, L; while (cin >> x >> y >> m >> n >> L) { // extend_gcd(240, 46); // x + km - (y + kn) = cL // => // (x - y) + k(m - n) = cL // => // k(n - m) + cL = (x - y) long long a = n - m, b = L, R = x - y; long long g, x0, y0; extend_gcd(a, b, g, x0, y0); // cout << "a: " << a << ", b: " << b << ", R: " << R << endl; // cout << "g: " << g << ", x0: " << x0 << ", y0: " << y0 << endl; if (R % g != 0) { cout << "Impossible" << endl; } else { long long k = R / g * x0; long long add = b / g; if (add < 0) { add = -add; } cout << (k % add + add) % add << endl; } } return 0; }