[藍橋杯] 最大比例
峰值內存消耗 < 256M CPU消耗 < 3000ms
【題目描述 - Problem Description】
X星球的某個大獎賽設了M級獎勵。每個級別的獎金是一個正整數。
並且,相鄰的兩個級別間的比例是個固定值。
也就是說:所有級別的獎金數構成了一個等比數列。
比如: 16,24,36,54
其等比值為:3/2
現在,我們隨機調查了一些獲獎者的獎金數。
請你據此推算可能的最大的等比值。
輸入格式:
第一行為數字N(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 |
【題解】
等比數列求公比,Xi < 10^12
先對各項排序,兩兩相除並約分,只要保證每次計算結果大於1,最后剩下的就是最大公比。
N=100,O(N*N)還算可以接受。
需要注意去重,以及公比為1的情況。
數據范圍10^12看起來誠惶誠恐,直接欽定long long可能會有人擔心出現10^24的情況,(因為強迫症)於是就寫了簡單的證明……
設等比數列通項:
由於都是整數項,遇到分數形式的公比必然為整除。
因此z, m < 10^12
在第一輪除法中,首項被消除,只留下公比的任意次冪,小於1則分子分母互換。
運算中由於GCD的存在:
因此在第一輪的計算峰值不會超過10^12次方
在第2~n輪的計算中,由於去除了不確定的首項,可以把通項轉化如下(其實一開始去掉首項也一樣):
兩兩相除時:
很遺憾,計算峰值還是無法超過10^12
【代碼 C++】
1 #include <cstdio> 2 #include <algorithm> 3 struct fs { 4 __int64 fz, fm; 5 bool operator == (const fs &B)const { 6 if (B.fz != fz || B.fm != fm) return 0; 7 return 1; 8 } 9 }data[105]; 10 __int64 rd[105]; 11 __int64 GCD(__int64 a, __int64 b) { 12 __int64 c; 13 while (c = a%b) a = b, b = c; 14 return b; 15 } 16 fs slv(fs a, fs b) { 17 if (a == b) return a; 18 __int64 gcd; 19 gcd = GCD(a.fz, b.fz); 20 a.fz /= gcd; b.fz /= gcd; 21 gcd = GCD(a.fm, b.fm); 22 a.fm /= gcd; b.fm /= gcd; 23 a.fz *= b.fm; 24 b.fz *= a.fm; 25 if (a.fz > b.fz) a.fm = b.fz; 26 else a.fm = a.fz, a.fz = b.fz; 27 return a; 28 } 29 int main() { 30 int i, j, n; 31 scanf("%d", &n); 32 for (i = 0; i < n; ++i) scanf("%I64d", rd + i), data[i].fm = 1; 33 std::sort(rd, rd + n); 34 for (i = j = 0; i < n; ++i) if (rd[i] != rd[i + 1]) data[j++].fz = rd[i]; 35 for (n = j - 1; n; --n) { 36 for (i = 0; i < n; ++i) data[i] = slv(data[i], data[i + 1]); 37 } 38 if (j == 1) puts("1/1"); 39 else printf("%I64d/%I64d", data[0].fz, data[0].fm); 40 return 0; 41 }