问题描述
在一个神秘的森林里,住着一个小精灵名叫小蓝。有一天,他偶然发现了一个隐藏在树洞里的宝藏,里面装满了闪烁着美丽光芒的宝石。这些宝石都有着不同的颜色和形状,但最引人注目的是它们各自独特的 “闪亮度” 属性。每颗宝石都有一个与生俱来的特殊能力,可以发出不同强度的闪光。小蓝共找到了 N 枚宝石,第 ii 枚宝石的 “闪亮度” 属性值为 HiHi,小蓝将会从这 N 枚宝石中选出三枚进行组合,组合之后的精美程度 S 可以用以下公式来衡量:
S=(HaHbHc*LCM(Ha,Hb,Hc))/(LCM(Ha,Hb)⋅LCM(Ha,Hc)LCM(Hb,Hc))
其中 LCM 表示的是最小公倍数函数。
小蓝想要使得三枚宝石组合后的精美程度 S 尽可能的高,请你帮他找出精美程度最高的方案。如果存在多个方案 S 值相同,优先选择按照 H 值升序排列后字典序最小的方案。
输入格式
第一行包含一个整数 N 表示宝石个数。
第二行包含 N 个整数表示 N 个宝石的 “闪亮度”。
输出格式
输出一行包含三个整数表示满足条件的三枚宝石的 “闪亮度”。
样例输入
5
1 2 3 4 9
样例输出
1 2 3
思路:
这道题确实很难。。。。。
这道题目要求从给定的宝石中选出三颗,使得它们的精美程度S最大。S的计算公式结合了三个数的乘积和它们的最小公倍数(LCM)关系。通过分析,我们发现S的最大值实际上等于这三个数的最大公约数(GCD)。因此,解题关键在于找到具有最大可能GCD的三个数,并且在多个候选组合中选择字典序最小的。
-
预处理因数:对于每个宝石的闪亮度,预处理其所有因数,并将该宝石存入对应因数的列表中。每个因数最多保留三个最小的数(按升序处理)。
-
逆序查找最大GCD:从最大的可能因数开始遍历,检查每个因数对应的列表中是否存在三个数,这三个数的最大公约数等于当前因数。若存在,直接输出这三个数(保证字典序最小)。
-
输入与排序:读取输入并将宝石的闪亮度按升序排列,以便后续处理时保留较小的数,确保字典序。
-
预处理因数列表:遍历每个数,找到其所有因数,并将该数存入对应因数的列表中。每个列表最多保留三个数。
-
寻找最优解:从最大的因数开始检查,若某个因数对应的列表中存在三个数且它们的最大公约数等于该因数,则输出这三个数。
代码:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX=1e5+10;
ll n;
ll a[MAX];
vector<vector<int> > v(MAX);//vector<int> v[MAX] v[d]保存所有d的倍数中的前三个最小数
int main()
{
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
sort(a,a+n); // 升序排序,保证字典序最小
// 预处理每个数的因数,将数存入对应因数的列表中
for(int i=0;i<n;i++)
{
// 对每个数 h[i],枚举所有可能的因数 j。由于因数是成对出现的(如 j 和 h[i]/j),只需遍历到 j <= sqrt(h[i])。
for(int j=1;j*j<=a[i];j++)
{
if (a[i] % j == 0) {
if (v[j].size() < 3) {
v[j].push_back(a[i]);
}
//如果 h[i] 不是平方数(避免重复添加),将 h[i] 加入因数 h[i]/j 的列表。
if(j!=a[i]/j&&v[a[i]/j].size()<3)
v[a[i]/j].push_back(a[i]);
}
}
}
// 从大到小遍历所有可能的d,寻找最大的GCD
for (int i = 1e5; i >= 1; i--) {
if (v[i].size() >= 3) {
// 计算三个数的最大公约数是否为i
int t = v[i][0], b = v[i][1], c = v[i][2];
if (__gcd(t, __gcd(b, c)) == i) {
cout << t << ' ' << b << ' ' << c << endl;
return 0;
}
}
}
return 0;
}