1223.最大比例(蓝桥杯)

代码
#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

typedef long long ll; 

const int N = 110;

ll a[N], fz[N],fm[N];

ll gcd(ll x, ll y)
{
    return y ? gcd(y, x % y) : x;
}

//这里之所以弃用辗转相除法的原因,是因为虽然更相减损术效率更低,
//但是它能有效地避免q为其他数的次方得到的数,比如9/4 可以为 2/3的平方

//假设原数列为 a,a*(p/q)^1,a*(p/q)^2,...,a*(p/q)^(n-1)
//假设抽取的数列  b0,b1,...,b(N-1)  (从小到大排好序了)
//  b1/b0,b2/b0,...,b(N-1)/b0-->  (p/q)^x1,(p/q)^x2,...,(p/q)^x(N-1)
//  我们要求的是:  (p/q)^k  (p/q)>1,所以使k最大,即求(p/q)^x1~(p/q)^x(N-1)的最大公约数,其实就是求x1~x(N-1)的最大公约数
//这里我们使用更相减损术,因为我们没有得到确切的x1~x(N-1)是多少,我们只有(p/q)^x1,(p/q)^x2,...,(p/q)^x(N-1)这些的值
//我们这里要用更相减损术的是指数,所以要让(p/q)^x1,(p/q)^x2,...,(p/q)^x(N-1),两两计算,
//互除,除到结果为1,即x1=x2,此时幂次为0,结果为1,这其实就是y总的思路,再次感叹y总的才华
//把分子分母分别去算,结果是相同的因为,分子分母的幂次是相同的
ll gcd_sub(ll x, ll y)//更相减损
{
    if(x < y) swap(x, y);
    if(y == 1) return x;//因为是对指数的更相减损术,此时幂次为0,则y为1,x即为最后的需要得到的比例数
    return gcd_sub(y, x / y);//因为是对指数的更相减损术 所以用除法
}

int main()
{
    
    int n; cin >> n;
    int cnt = 0;
    for(int i = 0; i < n; i++) cin >> a[i];
    
    sort(a, a + n);//排序
    
    for(int i = 1; i < n; i ++)
    {
        if(a[i] != a[i -1])//保证两两不相等
        {
          ll d = gcd(a[0], a[i]);
          fz[cnt]=a[i] / d;//指数的分子
          fm[cnt]=a[0] / d;//指数的分母
          cnt ++;
        }
    }
    ll up=fz[0], down = fm[0];
    
      for(int i = 1; i < cnt; i ++)
    {
        up = gcd_sub(up, fz[i]);
        down = gcd_sub(down, fm[i]);
    }
    
    cout << up <<'/' << down << endl;
    return 0;
}
感悟
首先,是对辗转相除法的复习
其次,是对更相减损法的学习,正宗的更相减损法是
int gcd_sub(int x, int y)
{
   if(x < y) swap(x, y);
   if(x == y) return x;
   return (y, x - y);
 }	

而这是用到了更相减损法的原因是:

想要求的对于n个数来说,在求得每两个数指数的最大公约数的条件下的最大公约数。

所以这里用到的更相减损法是:

ll gcd_sub(ll x, ll y)//更相减损
{
    if(x < y) swap(x, y);
    if(y == 1) return x;//因为是对指数的更相减损术,此时幂次为0,则y为1,x即为最后的需要得到的比例数
    return gcd_sub(y, x / y);//因为是对指数的更相减损术 所以用除法
}


通过这种方法,得到最后的,最简的最大比例系数。而这里没有用辗转相除法的原因是因为需要将每个数分解质因数,然后再对每个质因子的次数求最大公约数,这样写会很麻烦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值