题目描述:
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
分析步骤:
第一:思路分析:
-
我们拿到这道题目,就知道要求的是可能的等比数列中最大的比例。而且这个比例是个分数,所以我们的初步想法就是得分别计算我们的分子和分母,这是本体的第一个特点。
-
其次,我们将数组排个序之后,求出每个数和数组第一个数的最大公约数,在分别计算我们的分子数组和分母数组,求出公约数这是本题的第二个特点。
-
然后,我们可以想一下我们如何去求解出我们的公约数,对于这道题目我们不能仅仅只用辗转相除法,因为此式子是分式,如果运用辗转相除法就会出现错误。例如(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。
-
具体步骤如下:
-
若 a 等于 b,则最大公约数即为 a(或 b),结束计算;
-
若 a 大于 b,则用 a 减去 b,得到一个新的数作为 a,继续执行步骤 1;
-
若 a 小于 b,则将 b 减去 a,得到一个新的数作为 b,继续执行步骤 1;
-
重复以上步骤,直到 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;
}