CodeForces 281B

这道题直接枚举就行了。关键是注意精度。

不过,我看完题时,想到了 《具体数学》 4.5 介绍的 Stern-Brocot tree。通过它可以构造出所有 >= 0 的最简分数。并且这个 tree 有一个优美的性质,给出一个大于0的实数r,我们能以二叉搜索的方式在树上搜索最接近r的最简分式。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cassert>
#include <algorithm>
#include <cmath>
#include <limits>
#include <set>

using namespace std;

#define MIN(a, b) a < b ? a : b
#define MAX(a, b) a > b ? a : b
#define F(i, n) for (int i=0;i<(n);++i)
#define REP(i, s, t) for(int i=s;i<=t;++i)
#define UREP(i, s, t) for(int i=s;i>=t;--i)
#define REPOK(i, s, t, o) for(int i=s;i<=t && o;++i)
#define MEM0(addr, size) memset(addr, 0, size)
#define LBIT(x) x&-x

#define PI 3.1415926535897932384626433832795
#define HALF_PI 1.5707963267948966192313216916398
#define eps 1e-15

#define MAXN 30
#define MAXM 100000
#define MOD 1000000007

typedef long long LL;

const double maxdouble = numeric_limits<double>::max();

LL gcd(LL a, LL b);

#define DEBUG
#define ALGO2

int cmp_double(double a, double b)
{
    if (a - b > eps) return 1;
    if (a - b < -eps) return -1;
    return 0;
}

int cmp(LL a, LL b, LL x, LL y)
{
    if (!y)
        return -1;
    if (!b)
        return 1;
    return cmp_double((double)a/b, (double)x/y);
}


void Sub(LL a, LL b, LL x, LL y, double & ret)
{
    if (!b) {
        ret = maxdouble;
        return;
    }
    ret = (double)a / b - ((double)x / y);
}

void print(LL a, LL b) {
    cout << a << "/" << b << endl;
}
int main()
{
    freopen("input.in", "r", stdin);
    //freopen("input.in", "w", stdout);
    LL x, y, n;
    cin >> x >> y >> n;
    LL la, lb, ra, rb, a, b;
    bool equ;

    la = 0;
    lb = 1;
    ra = 1;
    rb = 0;
    equ = false;
    int g = gcd(x, y);
    x /= g;
    y /= g;
    for(;;) {
        if (lb + rb > n)
            break;
        a = la + ra;
        b = lb + rb;
#ifdef ALGO2
        int re = cmp(a, b, x, y);
#endif
        if (re > 0) {
            ra = a;
            rb = b;
        } else if (re < 0) {
            la = a;
            lb = b;
        } else {
            equ = true;
            break;
        }
    }

    if (equ)
        print(a, b);
    else {
        LL a1, b1, a2, b2;
        double z1, z2;
#ifdef ALGO2
        Sub(ra, rb, x, y, z1);
        Sub(x, y, la, lb, z2);
        int re = cmp_double(z1, z2);
#endif // ALGO2
        if (re > 0) {
            print(la, lb);
        } else if (re < 0) {
            print(ra, rb);
        } else {
            if (lb < rb) {
                print(la, lb);
            } else if (lb > rb) {
                print(ra, rb);
            } else {
                if (la <= ra)
                    print(la, lb);
                else
                    print(ra, rb);
            }
        }
    }

    return 0;
}

LL gcd(LL a, LL b)
{
    return b == 0 ? a : gcd(b, a % b);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值