【洛谷 P8636】[蓝桥杯 2016 省 AB] 最大比例 题解(数论+集合+辗转相除法)

12 阅读2分钟

[蓝桥杯 2016 省 AB] 最大比例

题目描述

X 星球的某个大奖赛设了 MM 级奖励。每个级别的奖金是一个正整数。

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

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

16,24,36,5416,24,36,54

其等比值为:3/23/2

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

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

输入格式

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

第二行 NN 个正整数 Xi(Xi<1012)X_i(X_i<10^{12}),用空格分开。每个整数表示调查到的某人的奖金数额。

输出格式

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

测试数据保证了输入格式正确,并且最大比例是存在的。

样例 #1

样例输入 #1

3
1250 200 32

样例输出 #1

25/4

样例 #2

样例输入 #2

4
3125 32 32 200

样例输出 #2

5/2

样例 #3

样例输入 #3

3
549755813888 524288 2

样例输出 #3

4/1

提示

时限 3 秒, 256M。蓝桥杯 2016 年第七届省赛

蓝桥杯 2016 年省赛 A 组 J 题(B 组 J 题)。


思路

首先,定义两个全局变量:一个 set 和一个 vector,分别用来存储输入的奖金数额和它们的比例。还定义了两个函数 gcdgcd2,都使用了辗转相除法。

main 函数中,首先读取奖金数额的数量,然后读取每个奖金数额,并将其插入到 set 中。由于 set 会自动排序和去重,所以这里可以直接得到排序后的奖金数额。

接着,遍历排序后的奖金数额,计算相邻两个数额的比例,并将结果存入 vector 中。这里使用了 reduce 函数来约分,即使得分数的分子分母互质。

最后,遍历存储比例的 vector,使用 gcd2 函数,计算所有分数的最大公约数。最后的结果就是可能的最大等比值。


AC代码

#include <algorithm>
#include <cmath>
#include <iostream>
#include <set>
#include <vector>
#define AUTHOR "HEX9CF"
using namespace std;
using ll = long long;
using pll = pair<ll, ll>;

const int N = 1e6 + 7;
const int INF = 0x3f3f3f3f;
const ll MOD = 1e9 + 7;

int n;
set<ll> s1;
vector<pll> v1;

ll gcd(ll a, ll b) { return (b ? gcd(b, a % b) : a); }

pll reduce(pll x) {
	ll g = gcd(x.first, x.second);
	return {x.first / g, x.second / g};
}

ll gcd2(ll a, ll b) {
	if (a < b) {
		swap(a, b);
	}
	return ((b == 1) ? a : gcd2(b, a / b));
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);

	cin >> n;
	for (int i = 0; i < n; i++) {
		ll x;
		cin >> x;
		s1.insert(x);
	}
	auto it1 = s1.begin();
	auto it2 = it1;
	for (it2++; it2 != s1.end(); it1++, it2++) {
		// cout << *it1 << " " << *it2 << endl;
		v1.push_back(reduce({*it2, *it1}));
	}
	pll ans = v1.front();
	auto it3 = v1.begin() + 1;
	for (; it3 != v1.end(); it3++) {
		ans.first = gcd2(ans.first, it3->first);
		ans.second = gcd2(ans.second, it3->second);
	}
	cout << ans.first << "/" << ans.second << "\n";
	return 0;
}