Online JudgeProblem SetAuthorsOnline ContestsUser
Web Board
Home Page
F.A.Qs
Statistical Charts
Problems
Submit Problem
Online Status
Prob.ID:
Register
Update your info
Authors ranklist
Current Contest
Past Contests
Scheduled Contests
Award Contest
User ID:
Password:
  Register

1000组数据某些不慎靠谱,不要被吓到 (注意,坐标x,y应该在总长L的范围内,且题目说明了x != y;1000组数据中大量x, y > L的情形,且某些x=y(mod L),这些undefined behavior自然可以引发各种答案)

Posted by KevinSayHi at 2013-04-16 05:01:22 on Problem 1061
附上详注正解一则:

/**
 * 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:
User ID:
Password:
Title:

Content:

Home Page   Go Back  To top


All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator