最大比例(acwing,蓝桥杯)

题目描述:

X星球的某个大奖赛设了 M 级奖励。

每个级别的奖金是一个正整数。

并且,相邻的两个级别间的比例是个固定值。

也就是说:所有级别的奖金数构成了一个等比数列。

比如:16,24,36,54,其等比值为:3/2。

现在,我们随机调查了一些获奖者的奖金数。

请你据此推算可能的最大的等比值。

输入格式:

第一行为数字 N ,表示接下的一行包含 N 个正整数。

第二行 N 个正整数 Xi,用空格分开,每个整数表示调查到的某人的奖金数额。

输出格式:

一个形如 A/B 的分数,要求 A、B 互质,表示可能的最大比例系数。

数据范围:

0<N<100
0<Xi<10^12
数据保证一定有解。

输入样例1:

3
1250 200 32

输出样例1:

25/4

输入样例2:

4
3125 32 32 200

输出样例2:

5/2

输入样例3:

3
549755813888 524288 2

输出样例3:

4/1

分析步骤:

第一:思路分析:

  1. 我们拿到这道题目,就知道要求的是可能的等比数列中最大的比例。而且这个比例是个分数,所以我们的初步想法就是得分别计算我们的分子和分母,这是本体的第一个特点

  2. 其次,我们将数组排个序之后,求出每个数和数组第一个数的最大公约数,在分别计算我们的分子数组和分母数组,求出公约数这是本题的第二个特点

  3. 然后,我们可以想一下我们如何去求解出我们的公约数,对于这道题目我们不能仅仅只用辗转相除法,因为此式子是分式,如果运用辗转相除法就会出现错误。例如(3/2)^2,(3/2)^4,(3/2)^6这个相除的q[N]数组如果使用辗转相除法求出的就不会是(3/2)^2,而是3/2.这就是原因,所以得用辗转相减法。这是本题的第三个特点

  第二:书写主函数,构建整体框架:

  • 我们先输入值,再排个序保证我们的数组序列是从小到大的,因为等比数组有一定顺序的.

  • 进入我们的for循环首先去重,因为题目提到有可能有重复的。

  • 利用d去求解我们的最大公约数,这里求解最大公约数是可以运用辗转相除法的,因为现在我们不是算指数型的约数。

  • 得到最大公约数之后,分子是每个数都去除以最大公约数分母是让第一个数去除以最大公约数down[cnt] 一直用 q[0] 除以最大公约数 d 是因为在计算分数的最简形式时,我们需要保持分母一致。而在这里,选择了 q[0] 作为所有分母的基准值,确保了分母的一致性,从而使得分数的比较和化简更加方便。

  • 至此我们的分子分母的数组就已经求解完毕

  • 之后我们就得运用辗转相减法求解分子分母的指数最大公约数。并进行动态的更新,最终的答案就是nn和mm。

int main()
{
    cin>>n;
    for(int i = 0 ; i < n ; i ++){
        cin>>q[i];
    }    
    sort(q , q + n);
    for(int i = 1 ; i < n ; i ++){
        if(q[i] != q[i - 1]){
        LL d = gcd(q[i] , q[0]);
        up[cnt] = q[i] / d;
        down[cnt] = q[0] / d;
        cnt++;
        }
    }
        
    LL nn = up[0],mm = down[0];//up分子 down分母
    for(int i=1;i<cnt;i++)//分开求分子分母的指数最大公约数
    {
        nn = gcd_sub(nn,up[i]);
        mm = gcd_sub(mm,down[i]);
    }
    cout<<nn<<"/"<<mm;    
    return 0;
}

  第三:辗转相除/减法 :

LL gcd(int a, int b)  // 欧几里得算法
{
    return b ? gcd(b, a % b) : a;
}

LL gcd_sub(int a , int b){
    if(b > a) swap(a,b);
    if(b == 1 ) return a;
    return gcd_sub(b,a/b);
}
  • 辗转相减法(又称欧几里得算法)是一种用来计算两个整数的最大公约数的方法。其基本思想是:若两个正整数 a 和 b(a > b)的最大公约数为 c那么 a 和 b 的差值 a - b 和 b 的最大公约数也是 c

  • 具体步骤如下:

  1. 若 a 等于 b,则最大公约数即为 a(或 b),结束计算;

  2. 若 a 大于 b,则用 a 减去 b,得到一个新的数作为 a,继续执行步骤 1

  3. 若 a 小于 b,则将 b 减去 a,得到一个新的数作为 b,继续执行步骤 1;

  4. 重复以上步骤,直到 a 等于 b,此时的 a(或 b)即为最大公约数。

  •      辗转相减法在实际应用中可能会有效率问题,因为每次减法运算都会有一定的开销。但是在某些特定情况下,它可以更快地找到最大公约数,例如当两个数相差较大时。

代码:

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 150;

LL n , cnt , q[N]; 
LL up[N] , down[N];

LL gcd(int a, int b)  // 欧几里得算法
{
    return b ? gcd(b, a % b) : a;
}

LL gcd_sub(int a , int b){
    if(b > a) swap(a,b);
    if(b == 1 ) return a;
    return gcd_sub(b,a/b);
}

int main()
{
    cin>>n;
    for(int i = 0 ; i < n ; i ++){
        cin>>q[i];
    }    
    sort(q , q + n);
    for(int i = 1 ; i < n ; i ++){
        if(q[i] != q[i - 1]){
        LL d = gcd(q[i] , q[0]);
        up[cnt] = q[i] / d;
        down[cnt] = q[0] / d;
        cnt++;
        }
    }
        
    LL nn = up[0],mm = down[0];//up分子 down分母
    for(int i=1;i<cnt;i++)//分开求分子分母的指数最大公约数
    {
        nn = gcd_sub(nn,up[i]);
        mm = gcd_sub(mm,down[i]);
    }
    cout<<nn<<"/"<<mm;    
    return 0;
}
  • 19
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值