洛谷 P2118 [NOIP 2014 普及组] 比例简化 题解

题目链接

洛谷 P2118 [NOIP 2014 普及组] 比例简化

思路分析

首先,观察到 \(l\) 的范围比较小,考虑枚举 \(A'\)。由题意 \(\frac{A'}{B'}\ge\frac{A}{B}\),则 \(B'\le\frac{B\times A'}{A}\)。又因为 \(B'\in\Z\),所以 \(B'_{\max}=\lfloor\frac{B\times A'}{A}\rfloor\)。但是,这道题目的坑来了,如果 \(B'_{\max}>L\),不意味着无法成立,还可能取 \(B'=L\),所以应该让 \(B'=\min(\lfloor\frac{B\times A'}{A}\rfloor,L)\)

然后,坑 \(2\) 又来了。根据初中数学知识,分母不为 \(0\),而 \(B'\) 又恰好在分母,所以如果 \(B'_{\max}=0\),那么 \(B'\) 就没有正整数可以取了,要直接 continue 掉。

最后,如何选出差值最小的呢?由于比较差值都要减去 \(\frac{A}{B}\),不妨给两边都加上一个 \(\frac{A}{B}\),则只需比较两个分数大小即可,交叉相乘一下,若 \(\frac{a}{b}<\frac{c}{d}\),则 \(ad<bc\),可以避免浮点数精度问题,同时乘法相比除法稍微更快一点。

小优化

观察到当 \(A',B'\) 不互质时,化简后的结果 \(A''\) 必定小于 \(A'\),所以已经被处理过,就不用再考虑了,时间复杂度优化至 \(O(L)\)

代码呈现

#include<bits/stdc++.h>
using namespace std;

int a,b,l;

// int gcd(int a,int b){ return b?gcd(b,a%b):a; }
int main(){
    scanf("%d%d%d",&a,&b,&l);
    int s1=-1,s2=-1;
    for (int i=1;i<=l;++i){
        int j=min(i*b/a,l);
        if (j==0/* || gcd(i,j)!=1*/) continue;
        if ((s1==-1 && s2==-1) || i*s2<j*s1) s1=i,s2=j;
    }
    printf("%d %d",s1,s2);
    return 0;
}
posted @ 2026-05-05 21:53  CodingJuRuo  阅读(9)  评论(0)    收藏  举报