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

文章讲述了如何根据给定的奖金数额数据,利用算法求解最大比例系数,涉及数据处理、比例计算和互质性处理。
摘要由CSDN通过智能技术生成

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

题目描述

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

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

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

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

其等比值为: 3 / 2 3/2 3/2

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

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

输入格式

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

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

输出格式

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

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

样例 #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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值