Online Judge | Problem Set | Authors | Online Contests | User | ||||||
---|---|---|---|---|---|---|---|---|---|---|
Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest |
1000组数据某些不慎靠谱,不要被吓到 (注意,坐标x,y应该在总长L的范围内,且题目说明了x != y;1000组数据中大量x, y > L的情形,且某些x=y(mod L),这些undefined behavior自然可以引发各种答案)附上详注正解一则: /** * date.c * POJ 1061 * Created by ************ on 04/15/2013. * -------------------------------------- * Mathematics (number theory). */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> #include <assert.h> typedef long long arith_t; // arithmetic type static inline arith_t linear_congruence_equation_solver(arith_t a, arith_t b, arith_t n); static arith_t gcd(arith_t x, arith_t y); static void bezout(arith_t x, arith_t y, arith_t *u, arith_t *v); static arith_t inverse(arith_t a, arith_t n); int main(int argc, const char *argv[]) { arith_t x, y, m, n, l; scanf("%lld %lld %lld %lld %lld\n", &x, &y, &m, &n, &l); // x + m t = y + n t (mod l) // (m - n) t = y - x (mod l) // we have x != y if (m == n) { printf("Impossible\n"); } else { arith_t t = linear_congruence_equation_solver(m - n, y - x, l); if (t == 0) { printf("Impossible\n"); } else { printf("%lld\n", t); } } return 0; } /** * Solves the congruence equation * a x = b (mod n) * and returns the minimal positive solution. If there is no solution, 0 is * returned. * * Requirements: * a != 0, b != 0, n > 0. * * Algorithm: * First, let a be positive (if not, negate both a and b). Next, let b be * in the range [1, n-1] (taking positive remainder). * * Then, reduce a and n to coprime. Let * g = gcd(a, n). * If g does not divide b, no solution (return 0). Otherwise we get * a0 = a/g, b0 = b/g, n0 = n/g * a0 x = b0 (mod n0). * Then we get the inverse x0 = a0^{-1} (mod n0) (x0 is gauranteed to be * positive by function inverse), so the general solution is * x = x0 * b0 (mod n0), * and the minimal positive solution is * (x0 * b0) % n0. */ static inline arith_t linear_congruence_equation_solver(arith_t a, arith_t b, arith_t n) { if (a < 0) { a = -a; b = -b; } b = (b % n + n) % n; arith_t g = gcd(a, n); if (b % g != 0) { return 0; } arith_t a0 = a / g; arith_t b0 = b / g; arith_t n0 = n / g; arith_t x0 = inverse(a0, n0); return (x0 * b0) % n0; } /** * Greatest common divisor. * * Requirement: * x > 0, y > 0. */ static arith_t gcd(arith_t x, arith_t y) { if (x % y == 0) { return y; } else { return gcd(y, x % y); } } /** * Given coprime x and y, calculate u and v for the Bezout formula: * u x + v y = 1. * * Requirements: * x > 0, y > 0 * return value satisfies: -y < u < y, and v depending on u * * Algorithm: * Euclidean algorithm. * If y == 1, let {u = 1, y = 1 - x}, return {u, v}; * If y > 1, let * y = x0 * x = q y + y0 * and by recursion * u0 x0 + v0 y0 = 1, * then * u0 y + v0 (x - q y) = 1, * namely * v0 x + (u0 - q v0) y = 1. * Therefore, let * u = v0 % y (C div, with positive/negative/0 remainder) * we have -y < u < y, and let * v = (1 - u x) / y * consequently. We return {u, v} at last. */ static void bezout(arith_t x, arith_t y, arith_t *u, arith_t *v) { if (y == 1) { *u = 1; *v = 1 - x; return; } arith_t x0 = y; arith_t y0 = x % y; arith_t u0, v0; bezout(x0, y0, &u0, &v0); *u = v0 % y; *v = (1 - (*u) * x) / y; return; } /** * Calculates the inverse of a in modulo n, namely, * a^{-1} (mod n). * * Requirement: * gcd(a, n) = 1. * return value satisfies: 1 <= a^{-1} <= n-1. */ static arith_t inverse(arith_t a, arith_t n) { arith_t u, v; bezout(a, n, &u, &v); // u is guaranteed to satisfy // -n < u < n // by bezout. // we need to get the positive remainder: return (u + n) % n; } Followed by: Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator