Problem
fraction
TimeLimit:10Sec
MemoryLimit:259MB
Description
给出4个正整数a,b,c,d,求一个最简分数qp满足ba<qp<dc。
若有多组解,输出q最小的一组,若仍有多组解,输出p最小的一组。
本题有多组数据,有若干行,每行4个数a,b,c,d。以文件的末尾作为结束。
Output
对于输入的每组数据输出一个最简分数qp。
1 2 3 4
| 1 3 1 2 2 1 3 1 2 1 4 1 1000 1001 1001 1002
|
Sample Output
HINT
对于100%的数据1≤a,b,c,d≤109,1≤数据组数≤500
数据保证至少存在一个最简分数符合条件。
标签:类欧几里得
Solution
类欧几里得基础题。
设f(a,b,c,d)为满足ba<qp<dc的p,q,考虑将其转化为规模更小的问题。
- 若ba和dc间相差至少一个整数,则p为最小符合条件的整数,q为1
- 若a≤b且c≤d,则一定有等价不等式ab>pq>cd,于是将问题转化为f(d,c,b,a),求出pq后颠倒分子分母得到qp
- 若a>b或c>d,令t=⌊ba⌋,则有ba−bt<qp−qt<dc−dt,问题转化为f(a−bt,b,c−dt,d),求出qp−qt后即可还原出qp
由于每次均将参数变为其辗转相模的结果,故而复杂度和欧几里得算法大致相同。
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; }
|