第七屆藍橋杯省賽C++A/B組 最大比例
阿新 • • 發佈:2020-09-23
X星球的某個大獎賽設了M級獎勵。
每個級別的獎金是一個正整數。
並且,相鄰的兩個級別間的比例是個固定值。
也就是說:所有級別的獎金數構成了一個等比數列。
比如:16,24,36,54,其等比值為:3/2。
現在,我們隨機調查了一些獲獎者的獎金數。
請你據此推算可能的最大的等比值。
輸入格式
第一行為數字N,表示接下的一行包含NN個正整數。
第二行N個正整數Xi,用空格分開,每個整數表示調查到的某人的獎金數額。
輸出格式
一個形如A/B的分數,要求A、B互質,表示可能的最大比例係數。
資料範圍
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; }