【C++数论】P8636 [蓝桥杯 2016 省 AB] 最大比例|普及

本文涉及知识点

数论:质数、最大公约数、菲蜀定理

[蓝桥杯 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 题)。

证明过程

完整的等比数列,分解质因素后,各质因数的数量成等差数列,令其差为y。本题是残缺的等比数列,故质因素的数量是残缺的等差的数量。相邻两项的差分别为:k1y,k2y ⋯ \cdots ,下文简称k1、k2 ⋯ \cdots 任意元素或所有元素为k。对于任意质因数,k是未知的,但ky是已知的,就是下文的b[i]。如果k互质,则y就是gcd(ky)。如果k不互质,除以gcd(k)后,y更大。本题一定有解,故各质因数的k相同,即各质因数的y为gcd(ky)。如果ky为负数,结果是-gcd(ky)。由于倍率大于等于1,故正数(分子)取最大值,比负数(分母)取最大值更优。

解法

X升序排序。
获取x所有元素的质因数,出重。其实只要枚举任意两个不同的元素。
枚举各质因数z:
依次将x的包括z的次方放到数a中。b[i] = a[i+1]减a[i]。g = gcd(b)。
如果b全部为正,则分子包括:zg;否则分母包括zg。由于等差数量的差,要么全部为正,要么全部为负。

代码

核心代码

#include <iostream>
#include <sstream>
#include <vector>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<string>
#include<algorithm>
#include<functional>
#include<queue>
#include <stack>
#include<iomanip>
#include<numeric>
#include <math.h>
#include <climits>
#include<assert.h>

#include <bitset>
using namespace std;



template<class T = int>
vector<T> Read(int n,const char* pFormat = "%d") {
	vector<T> ret;
	T d ;
	while (n--) {
		scanf(pFormat, &d);
		ret.emplace_back(d);
	}
	return ret;
}

template<class T = int>
vector<T> Read( const char* pFormat = "%d") {
	int n;
	scanf("%d", &n);
	vector<T> ret;
	T d;
	while (n--) {
		scanf(pFormat, &d);
		ret.emplace_back(d);
	}
	return ret;
}

string ReadChar(int n) {
	string str;
	char ch;
	while (n--) {
		do
		{
			scanf("%c", &ch);
		} while (('\n' == ch));
			str += ch;
	}
	return str;
}

template<class T = int>
class CUniqueFactorization
{
public:
	CUniqueFactorization(T iPrime, int cnt) {
		m_data.emplace_back(iPrime, cnt);
	}
	CUniqueFactorization(vector<T> primes = {}, vector<int> cnts = {}) {
		for (int i = 0; i < primes.size(); i++) {
			m_data.emplace_back(primes[i], cnts[i]);
		}
	}
	CUniqueFactorization operator+ (const CUniqueFactorization& o)const {
		CUniqueFactorization ret;
		int i = 0, j = 0;
		while ((i < m_data.size()) && (j < o.m_data.size())) {
			if (m_data[i].first == o.m_data[j].first) {
				int cnt = m_data[i].second + o.m_data[j].second;
				if (0 != cnt)
				{
					ret.m_data.emplace_back(m_data[i].first, cnt);
				}
				i++, j++;
			}
			else if (m_data[i].first < o.m_data[j].first) {
				ret.m_data.emplace_back(m_data[i]);
				i++;
			}
			else {
				ret.m_data.emplace_back(o.m_data[j]);
				j++;
			}
		}
		ret.m_data.insert(ret.m_data.end(), m_data.begin() + i, m_data.end());
		ret.m_data.insert(ret.m_data.end(), o.m_data.begin() + j, o.m_data.end());
		return ret;
	}
	CUniqueFactorization negation()const {
		CUniqueFactorization ret;
		ret = *this;
		for (auto& [i, cnt] : ret.m_data) {
			cnt *= -1;
		}
		return ret;
	}
	CUniqueFactorization One() const {
		CUniqueFactorization ret;
		ret = *this;
		for (auto& [i, cnt] : ret.m_data) {
			cnt *= 1;
		}
		return ret;
	}
	CUniqueFactorization GetValue(const CUniqueFactorization& o)const {
		CUniqueFactorization ret;
		for (const auto& [pri, cnt] : m_data) {
			ret.m_data.emplace_back(pri, 0);
		}
		return ret + o;
	};
	pair<T, T> Union()const {
		long long ll1 = 1, ll2 = 1;
		for (auto [pri, cnt] : m_data) {
			auto& ll = (cnt >= 0) ? ll1 : ll2;
			for (int j = 0; j < abs(cnt); j++) {
				ll *= pri;
			}//可以用快速指数幂加速
		}
		return { ll1,ll2 };
	}
	vector<pair<T, int>> m_data;
};

template<class T = int>
class CUniqueFactorizationFactory {
public:
	CUniqueFactorizationFactory(T iMax) {
		T iMaxSqrt = sqrt(iMax) + 2;
		m_vPrime = CreatePrime(iMaxSqrt);
	}
	CUniqueFactorization<T> Factorization(T x) {
		CUniqueFactorization<T> ret;
		for (const auto& iPre : m_vPrime) {
			int cnt = 0;
			while (0 == x % iPre) {
				cnt++;
				x /= iPre;
			}
			if (cnt > 0) {
				ret.m_data.emplace_back(iPre, cnt);
			}
		}
		if (x > 1) {
			ret.m_data.emplace_back(x, 1);
		}
		return ret;
	}
	static vector<int> CreatePrime(int iMax)
	{
		vector<bool> isPrime(iMax + 1, true);
		vector<int> vPrime;
		for (int i = 2; i <= iMax; i++)
		{
			if (isPrime[i])
			{
				vPrime.emplace_back(i);
			}
			for (const auto& n : vPrime)
			{
				if (n * i > iMax) { break; }
				isPrime[n * i] = false;
				if (0 == i % n) { break; }
			}
		}
		return vPrime;
	}
	vector<int> m_vPrime;
};

class Solution {
public:
	pair<long long, long long> Ans(vector<long long>& a) {
		const int N = a.size();
		sort(a.begin(), a.end());
		unordered_map<long long, vector<int>> ma;
		CUniqueFactorizationFactory<long long> uff(a.back());
		CUniqueFactorization<long long> uf3;
		for (const auto& ii : a)
		{
			uf3 = uf3 + uff.Factorization(ii).One();
		}
		for (const auto& ii : a) {
			auto uf = uff.Factorization(ii);
			auto uf4 = uf3.GetValue(uf);
			for (const auto& [pri, cnt] : uf4.m_data) {
				ma[pri].emplace_back(cnt);
			}
		}
		CUniqueFactorization<long long> ret;
		for (const auto& [pri, v] : ma) {
			long long g = 0;
			int sign = 1;
			for (int i = 1; i < v.size(); i++) {
				g = gcd(g, v[i] - v[i - 1]);
				if (v[i] - v[i - 1] < 0) { sign = -1; }
			}
			ret = ret + CUniqueFactorization<long long>(pri, sign * g);
		}
		return ret.Union();
	}
};

int main() {
#ifdef _DEBUG
	freopen("a.in", "r", stdin);
#endif // DEBUG
	int n;
	scanf("%d", &n);	
	auto a = Read<long long>(n,"%lld");
#ifdef _DEBUG
	//Out(a, "a=");
#endif
	auto [ll1,ll2] = Solution().Ans(a);
	cout << ll1 << "/" << ll2  << std::endl;
	return 0;
}

单元测试

		vector<long long> a;
		TEST_METHOD(TestMethod1)
		{
			a = { 1,1,1 };
			auto [ll1, ll2] = Solution().Ans(a);
			AssertEx(1LL, ll1);
			AssertEx(1LL, ll2);
		}
		TEST_METHOD(TestMethod2)
		{
			a = { 2,10000000019LL };
			auto [ll1, ll2] = Solution().Ans(a);
			AssertEx(a[1], ll1);
			AssertEx(a[0], ll2);
		}
		TEST_METHOD(TestMethod3)
		{
			a = { 10000000019LL ,2};
			auto [ll1, ll2] = Solution().Ans(a);
			AssertEx((long long)a[1], ll1);
			AssertEx(a[0], ll2);
		}
		TEST_METHOD(TestMethod4)
		{
			a = { 1250 ,200, 32 };
			auto [ll1, ll2] = Solution().Ans(a);
			AssertEx((long long)25, ll1);
			AssertEx(4LL, ll2);
		}
		TEST_METHOD(TestMethod5)
		{
			a = { 3125, 32, 32 ,200 };
			auto [ll1, ll2] = Solution().Ans(a);
			AssertEx((long long)5, ll1);
			AssertEx(2LL, ll2);
		}
		TEST_METHOD(TestMethod6)
		{
			a = { 549755813888LL, 524288, 2 };
			auto [ll1, ll2] = Solution().Ans(a);
			AssertEx((long long)4, ll1);
			AssertEx(1LL, ll2);
		}

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

软件架构师何志丹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值