BZOJ2187 fraction <类欧几里得>

Problem

fraction

Time  Limit:  10  Sec\mathrm{Time\;Limit:\;10\;Sec}
Memory  Limit:  259  MB\mathrm{Memory\;Limit:\;259\;MB}

Description

给出44个正整数a,b,c,da,b,c,d,求一个最简分数pq\frac{p}{q}满足ab<pq<cd\frac{a}{b}<\frac{p}{q}<\frac{c}{d}
若有多组解,输出qq最小的一组,若仍有多组解,输出pp最小的一组。

Input

本题有多组数据,有若干行,每行44个数a,b,c,da,b,c,d。以文件的末尾作为结束。

Output

对于输入的每组数据输出一个最简分数pq\frac{p}{q}

Sample Input

1
2
3
4
1 3 1 2
2 1 3 1
2 1 4 1
1000 1001 1001 1002

Sample Output

1
2
3
4
2/5
5/2
3/1
2001/2003

HINT

对于100%100\%的数据1a,b,c,d1091\le a,b,c,d\le10^9,1数据组数5001\le 数据组数\le 500
数据保证至少存在一个最简分数符合条件。

标签:类欧几里得

Solution

类欧几里得基础题。

f(a,b,c,d)f(a,b,c,d)为满足ab<pq<cd\frac{a}{b}<\frac{p}{q}<\frac{c}{d}p,qp,q,考虑将其转化为规模更小的问题。

  • ab\frac{a}{b}cd\frac{c}{d}间相差至少一个整数,则pp为最小符合条件的整数,qq11
  • abcda\le b 且 c\le d,则一定有等价不等式ba>qp>dc\frac{b}{a}>\frac{q}{p}>\frac{d}{c},于是将问题转化为f(d,c,b,a)f(d,c,b,a),求出qp\frac{q}{p}后颠倒分子分母得到pq\frac{p}{q}
  • a>ba>bc>dc>d,令t=abt=\lfloor\frac{a}{b}\rfloor,则有abtb<pqtq<cdtd\frac{a-bt}{b}<\frac{p-qt}{q}<\frac{c-dt}{d},问题转化为f(abt,b,cdt,d)f(a-bt,b,c-dt,d),求出pqtq\frac{p-qt}{q}后即可还原出pq\frac{p}{q}

由于每次均将参数变为其辗转相模的结果,故而复杂度和欧几里得算法大致相同。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <bits/stdc++.h>
using namespace std;
typedef double dnt;
typedef long long lnt;
lnt gcd(lnt x, lnt y) {return y ? gcd(y, x%y) : x;}
lnt flr(lnt x, lnt y) {return (lnt)floor((dnt)x/(dnt)y);}
lnt cel(lnt x, lnt y) {return (lnt)ceil((dnt)x/(dnt)y);}
void getans(lnt a, lnt b, lnt c, lnt d, lnt &p, lnt &q) {
if (flr(a, b)+1 <= cel(c, d)-1) p = flr(a, b)+1, q = 1;
else if (!a) p = 1, q = flr(d, c)+1;
else if (a <= b && c <= d) getans(d, c, b, a, q, p);
else {lnt k = a/b; getans(a-b*k, b, c-d*k, d, p, q), p += q*k;}
}
int main() {
lnt a, b, c, d, p, q, t;
while (~scanf("%lld%lld%lld%lld", &a, &b, &c, &d))
t = gcd(a, b), a /= t, b /= t,
t = gcd(c, d), c /= t, d /= t,
getans(a, b, c, d, p, q),
printf("%lld/%lld\n", p, q);
return 0;
}