[蓝桥杯2016初赛]最大比例

问题

X星球的某个大奖赛设了M级奖励。每个级别的奖金是一个正整数。并且,相邻的两个级别间的比例是个固定值。 

也就是说:所有级别的奖金数构成了一个等比数列。比如:16,24,36,54。其等比值为:3/2。

现在,我们随机调查了一些获奖者的奖金数。请你据此推算可能的最大的等比值。 

输入

输入存在多组测试数据

第一行为数字 N (0<N<100),表示接下的一行包含N个正整数 

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

输出

对于每组测试数据,输出一个形如A/B的分数,要求A、B互质。表示可能的最大比例系数 

链接:最大比例

输入样例 

3

1250 200 32

4

3125 32 32 200

3

549755813888 524288 2

输出样例

25/4

5/2

4/1 


题解 

  观察32 200 3125 答案为5/2 可知完整的等比数列为 32, (80), 200, (500), (1250), 3125

  可知数列是缺项得到的,但我们将数列排序后,每两个数的比值一定是公比的倍数。例如200/32 = 25/4,可以由 5/2 平方得来,3125/200 = 125/8,可以由 5/2 立方得来。

  设一个有n项数列的公比p / q, 则任何项之间的比值一定是(p/q)^{1}, (p/q)^{2}, (p/q)^{3}... (p/q)^{n-1}中的一个。 因此给定一些比值后,这些比值必定可以变成公比的k次幂(1 <= k < n)。

由此,我们只需分别求出公比的分子和分母的幂的最大公约数即可。由于我们事先不知每项比值的幂,因此无法通过辗转相除法来做,而求幂的最大公约数可以通过辗转相减法来做。

这里证明一下为什么能用辗转相减法求幂的最大公约数。

首先得证明辗转相除法求最大公约数的原理。

假设有两个数 150 和 60,设它们的最大公约数为x。

显然150和60都能被x整除,150 | x = (90+60) | x

显然90和60都能被x整除,90 | x = (60 + 30) | x

显然60和30都能被x整除,60|x = (30 + 30) | x, 直到最后有一项为0,因此最大公约数为30。

从中我们可以得出一个结论:gcd(a,b) = gcd(a-b,b) (a > b)

其次证明辗转相减法的原理。

设有两个同底的数 f^{x},f^{y} (x > y), 则gcd(x, y) = gcd(x-y, y), (f^{x}, f^{y}) = (f^{x-y}, f^{y}) = (f^{x}/f^{y}, f^{y})


完整代码

 

#include<iostream>
#include<algorithm>
using namespace std;

typedef long long ll;
const int maxn = 110;
ll a[maxn], b[maxn], x[maxn];

ll gcd(ll a, ll b)
{
  return (!b)?a:gcd(b, a%b);
}

ll gcd_sub(ll a, ll b)
{
  if(a < b) swap(a, b);
  if(b == 1) return a;
  return gcd_sub(b, a/b);
}
int main()
{
    int n;
    while(cin >> n)
    {
      for(int i = 1; i <= n; i++) cin >> x[i];
      sort(x+1, x+1+n);
      int cnt = 0;
      for(int i = 2; i <= n; i++)
      {
        if(x[i] != x[i-1])
        {
          cnt++;
          ll tmp = gcd(x[i], x[i-1]);
          a[cnt] = x[i-1] / tmp;
          b[cnt] = x[i] / tmp;
        }
      }

      ll son = a[1], parent = b[1];
      for(int i = 2; i <= cnt; i++)
      {
        son = gcd_sub(son, a[i]);
        parent = gcd_sub(parent, b[i]);
      }

      cout << parent << "/" << son << endl;
    }


    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值