第七届蓝桥杯省赛C++A/B组 最大比例

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

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

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

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

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

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

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

输入格式

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

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

输出格式

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

数据范围

0<N<100
0<Xi<1012
数据保证一定有解。

输入样例1:

3
1250 200 32

输出样例1:

25/4

输入样例2:

4
3125 32 32 200

输出样例2:

5/2

输入样例3:z

3y
549755813888 524288 2

输出样例3:

4/1

我们假定首相为a,公比为q,那么对于S的每一项都是a*qx,对于S去重后从小到大排列的情况,后一项除以前一项就能消掉了a,我们得到了n-1个qn的新数列(我们即为S1),我们可以重复上述操作(去重,排序),直到只剩下一个qn的值,我们记为p,那我们如何确定q的值呢?
当我们确定了p的值后,对于我们将原数列从第二项开始每项除以第一项,这样能得到的数列origin每一个也是qx,(如果第一项是a*qx',确实后面的每项实际上是多除以了qx'的,但是这样可能造成q求得大了,例如a=3,q=2,第一项是6,接下来几项是24,96,384,这样q求出来是4,but,我们可以把a当成6,那么这样公比就为4了,这样4大于2而且也符合题意)那么我们通过S1的每个qn去不断除以p(因为p是S1经过多次后一项除以前一项得来的,所以p会小于S1的所有),直到出现S1的某项多次除以p后结果不为1且小于p,再次强调,p是qx,S1的每一项是qy,如果S1的某项多次除以p后不能整除且剩余的小于p,则说明剩余的项qz(z = y % x,因为每次除以qx,而qy/qx=qy-x),则此时的z是小于x的,通过S1数列的所有项都如此操作,就得到了q。
提问:最后的z会不会不为1,导致算出来的不是q?
答:如果不为1,那么说明所有的项均以qz为最大公比,那不就相当于我们一开始假设q为qz是一样的情况了。
提问:如果求得最后的z不是p的次方,那之前每次除以p不是错误的操作了嘛,不得从头除以现在算出来的qz嘛?
答:既然p是通过操作求解得到的,那么p一定是最大公比q的n次幂,我们求得了最新的qz一定是q的幂,所以最后求出最小的一定是q,那么之前是除以q还是p(p也是q的n次幂)都没有关系了。
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF = 0x3f3f3f3f3f3f3f3f;
struct Node{//构造分数结构体
    ll son, fa;
    Node(ll temp){
        fa = 1;
        son = temp;
    }
    Node(ll x, ll y){//x是分子,y是分母
        ll gcd = __gcd(x, y);
        son = x / gcd;
        fa = y / gcd;
    }
    Node(){}
    friend Node operator / (Node x, Node y){//分数除法
        ll gcd1 = __gcd(x.son, y.son);
        x.son /= gcd1;
        y.son /= gcd1;
        ll gcd2 = __gcd(x.fa, y.fa);
        x.fa /= gcd2;
        y.fa /= gcd2;
        return Node(x.son * y.fa, y.son * x.fa);
    }
    friend bool operator == (Node x, Node y){//分数判断相等
        return x.son == y.son && x.fa == y.fa;
    }
    friend bool operator < (Node x, Node y){//分数比较
        ll lcd = x.fa / __gcd(x.fa, y.fa) * y.fa;
        x.son *= lcd / x.fa;
        y.son *= lcd / y.fa;
        return x.son < y.son;
    }
};
vector<Node> v, origin;//v是原数列,origin是保留最后的S1数列
vector<Node> t;//t是在原数列上得到的新数列
Node ans;
int main()
{
    int n;
    ll temp;
    cin >> n;
    for(int i = 0; i < n; i++)
    {
        cin >> temp;
        v.push_back(Node(temp));
    }
    v.erase(unique(v.begin(), v.end()), v.end());//删除重复
    sort(v.begin(), v.end());//排序
//求解origin数列
    origin = v;
    for(int i = 1; i < origin.size(); i++)
    {
        origin[i] = origin[i] / origin[0];
    }
    while(v.size() != 1)//如果只剩一个了,跳出
    {
        for(int i = 1; i < v.size(); i++)
        {
            t.push_back(v[i] / v[i - 1]);//后一个除以前一个分数
        }
        v = t;
        t.clear();
        v.erase(unique(v.begin(), v.end()), v.end());
        sort(v.begin(), v.end());
        
    }
    ans = v[0];
    for(int i = 1; i < origin.size(); i++)//开始
    {
        while(!(origin[i] == Node(1)))
        {
            if(ans < origin[i] || origin[i] == ans)
                origin[i] = origin[i] / ans;
            else//如果剩下的小于ans,就说明ans可以更小,我们更新ans
                ans = origin[i];
        }
    }
    printf("%lld/%lld\n", ans.son, ans.fa);
    return 0;
}

 

 
posted @ 2020-09-23 17:49  funforever  阅读(395)  评论(0编辑  收藏  举报