Address: http://www.spoj.com/problems/FINFRAC/
Question:
Give four integers a, B, c, d, and look for two integers p, q, so that a/B <p/q <c/d, q is the smallest, if multiple solutions exist, finding p is the smallest.
Solution 1 (not strictly proven ):
There is a sequence called a mine sequence. The magic of a mine sequence is that if a/B <c/d, a/B <(a + c)/(B + d) <c/d, then there is a/B <(2a + c)/(2b + d) <(a + c)/(B + d) <(a + 2c) /(B + 2d) <c/d
We found that the more the score "Participate", the closer the result is to the previous score, and vice versa.
Inspired by this, set two weights x> 0 and y> 0 (if they are equal to 0, they cannot be strictly greater than or less than), with a/B <(xa + yc) /(xb + yd) <c/d
It can be proved that (xa + yc)/(xb + yd) can cover all the scores between a/B and c/d, so the p/q we require must be in this form.
The meaning requires that p and q be the smallest, so the gcd of (xa + yc) and (xb + yd) should be as big as possible, and then divide the gcd into smaller denominator.
The problem is converted to gcd (xa + yc, xb + yd), where abcd is known, x and y are for it, and gcd (ax + cy, bx + dy) is another method ), here, we can use Euclidean to perform division. For example.
A = 7, B = 5, c = 8, d = 5, then gcd (7x + 8y, 5x + 5y) = gcd (2x + 3y, 5x + 5y) = gcd (2x + 3y, 3x + 2y), so we can't continue. Because one side x is more than one side y, then we assume they are equal,
That is, 2x + 3y = 3x + 2y, and x = y. The formula is as follows: (7x + 8y)/(5x + 5y) = 15x/10x = 3/2.
The Code is as follows:
#include <stdio.h>#define LL long long#define ABS(x) ( (x) < 0 ? -(x) : (x) )LL gcd( LL a, LL b ) { while( b > 0 ) { LL t = a % b; a = b; b = t; } return a;}void solve( int a, int b, int c, int d, int& x, int& y ) { x = y = 1; int t1, t2; while(1) { t1 = t2 = 0x7fffffff; if( a >= b && c >= d ) { if( b > 0 ) t1 = a / b; if( d > 0 ) t2 = c / d; if( t1 > t2 ) t1 = t2; a -= t1 * b; c -= t1 * d; } else if( a <= b && c <= d ) { t1 = a; a = b; b = t1; t2 = c; c = d; d = t2; } else break; } x = ABS( c - d ); y = ABS( a - b ); if( x == 0 ) x = 1; if( y == 0 ) y = 1;}int main() { int a, b, c, d, x, y, tmp; LL p, q, tmp2; while( scanf( "%d%d%d%d", &a, &b, &c, &d ) == 4 ) { tmp = gcd( a, b ); a /= tmp; b /= tmp; tmp = gcd( c, d ); c /= tmp; d /= tmp; solve( a, b, c, d, x, y ); p = a * (LL)x + c * (LL)y; q = b * (LL)x + d * (LL)y; tmp2 = gcd( p, q ); printf( "%lld/%lld\n", p / tmp2, q / tmp2 ); } return 0;}
Solution 2 (read the online answer ):
If [a/B] is set, a/B is rounded down.
2.1 If a/B> = 1 and k = [a/B], you can know (a/B)-k <(p/q) -k <(c/d)-k, that is, (a-bk)/B <(p-qk)/q <(c-dk)/d, set a' = a-bk, p' = p-qk, C' = c-dk, after the solution of A'/B <P'/q <C'/d is obtained, p = P' + qk can obtain the true p and q. If you know a, B, q, p has another method (that is, you do not need to obtain p from recursion), that is, p = q * a/B.
+ 1 (if it is regarded as an integer), this is because p> q * a/B (if it is regarded as a floating point number), while the integer division will discard the remainder, so it just adds 1.
2.2 If a/B <1
2.2.1 If c/d> 1, p = q = 1
2.2.2 If c/d <= 1, the problem can be converted to d/c <q/p <B/
The Code is as follows:
#include <stdio.h>#define LL long longLL findq( LL a, LL b, LL c, LL d ) { if( a < b ) { if( c > d ) return 1; else return findq( d, c, b, a ) * d / c + 1; } else { LL k = a / b; return findq( a - k * b, b, c - k * d, d ); }}int main() { LL a, b, c, d, p, q; while( scanf( "%lld%lld%lld%lld", &a, &b, &c, &d ) == 4 ) { q = findq( a, b, c, d ); p = q * a / b + 1; printf( "%lld/%lld\n", p, q ); } return 0;}
References:
Http://apps.topcoder.com/forums/;jsessionid=627E3C18A18ED2AA6A5B4BDB4F1A0C3D? Module = RevisionHistory & amp; messageID = 1204829
Wxcc code: http://acm.hust.edu.cn/vjudge/contest/viewSource.action? Id = 192084