| ||||||||||
| 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