HDU 6209 二分分数

题目链接


思路:
简单转化之后,此题就是给你一个小数,叫你输出值最接近的分数,划成最简形式。

考虑二分分数。

若不知道起始范围,则可以从: 0 1 − 1 0 ( + o o ) \frac{0}{1} - \frac{1}{0}(+oo) 1001(+oo)
进行二分。

出于效率和最简分数的考虑,我们每次二分的值不是求端点的平均数。

比如对于 [ a b , c d ] [\frac{a}{b},\frac{c}{d}] [ba,dc],我们二分的新的分数为:
a + c b + d \frac{a+c}{b+d} b+da+c

然后进行比较而决定左移右移即可。


另外我们可以先算答案分数的整数值,来缩小起始的二分范围。

如果第一个不小于该小数的整数值为val,则范围应该为:
[ ( v a l − 1 ) 1 , v a l 1 ] [\frac{(val-1)}{1},\frac{val}{1}] [1(val1),1val]

代码:

#include<cstdio>
using namespace std;
typedef long long ll;
typedef long double lb;

ll k,lz,rz,lm,rm,val,A,B;
lb Mn,aim;

lb Abs(lb x){
    return x>0?x:-x;
}

int main(){
    int T;scanf("%d",&T);
    while(T--){
        ll k;
        scanf("%I64d",&k);
        val = 1;
        while(val*val*val < k*k) val++;
        if(val*val*val == k*k){
            printf("%I64d/1\n",val);
            continue;
        }
        lz = val-1,lm = 1;aim = k*k;
        rz = val,rm = 1;Mn = 1e60;
        while(1){
            ll a = lz + rz,b = lm + rm;
            if(b > 100000) break;
            lb u = a,v = b;
            lb now = u*u*u/v/v/v;
            if(Abs(now-aim) < Mn){
                Mn = Abs(now-aim);
                A = a,B = b;
            }
            if(now > aim){rz = a,rm = b;}
            else         {lz = a,lm = b;}
        }
        printf("%I64d/%I64d\n",A,B);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值