1. 程式人生 > 實用技巧 >第七屆藍橋杯省賽C++A/B組 最大比例

第七屆藍橋杯省賽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的值後,對於我們得到S1數列,每一個也是qy,那麼我們通過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[i-1];
    }
    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;
}