宝石组合 第十五届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组

宝石组合

题目来源

第十五届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组

原题链接

蓝桥杯 宝石组合 https://www.lanqiao.cn/problems/19711/learning/

问题描述

P10426 [蓝桥杯 2024 省 B] 宝石组合

题目描述

在一个神秘的森林里,住着一个小精灵名叫小蓝。有一天,他偶然发现了一个隐藏在树洞里的宝藏,里面装满了闪烁着美丽光芒的宝石。这些宝石都有着不同的颜色和形状,但最引人注目的是它们各自独特的 “闪亮度” 属性。每颗宝石都有一个与生俱来的特殊能力,可以发出不同强度的闪光。小蓝共找到了 n n n 枚宝石,第 i i i 枚宝石的 “闪亮度” 属性值为 H i H_i Hi,小蓝将会从这 n n n 枚宝石中选出三枚进行组合,组合之后的精美程度 S S S 可以用以下公式来衡量:

S = H a H b H c ⋅ LCM ⁡ ( H a , H b , H c ) LCM ⁡ ( H a , H b ) ⋅ LCM ⁡ ( H a , H c ) LCM ⁡ ( H b , H c ) S = H_a H_b H_c \cdot \frac{\operatorname{LCM}(H_a, H_b, H_c)}{\operatorname{LCM}(H_a, H_b) \cdot\operatorname{LCM}(H_a, H_c) \operatorname{LCM}(H_b, H_c)} S=HaHbHcLCM(Ha,Hb)LCM(Ha,Hc)LCM(Hb,Hc)LCM(Ha,Hb,Hc)

其中 LCM ⁡ \operatorname{LCM} LCM 表示的是最小公倍数函数。

小蓝想要使得三枚宝石组合后的精美程度 S S S 尽可能的高,请你帮他找出精美程度最高的方案。如果存在多个方案 S S S 值相同,优先选择按照 H H H 值升序排列后字典序最小的方案。

输入格式

第一行一个整数 n n n 表示宝石个数。
第二行有 n n n 个整数 H 1 , H 2 , … H n H_1, H_2, \dots H_n H1,H2,Hn 表示每个宝石的闪亮度。

输出格式

输出一行包含三个整数表示满足条件的三枚宝石的 “闪亮度”。

输入输出样例 #1

输入 #1

5
1 2 3 4 9

输出 #1

1 2 3

说明/提示

数据规模与约定

  • 30 % 30\% 30% 的数据, n ≤ 100 n \leq 100 n100 H i ≤ 1 0 3 H_i \leq 10^3 Hi103
  • 60 % 60\% 60% 的数据, n ≤ 2 × 1 0 3 n \leq 2 \times 10^3 n2×103
  • 对全部的测试数据,保证 3 ≤ n ≤ 1 0 5 3 \leq n \leq 10^5 3n105 1 ≤ H i ≤ 1 0 5 1 \leq H_i \leq 10^5 1Hi105

问题分析

解决该问题的关键便是化简精美程度S的计算公式。

要点1:最小公倍数与最大公因数相关公式

a , b a,b a,b 的最小公倍数 l c m ( a , b ) lcm(a,b) lcm(a,b)
a , b a,b a,b 的最大公因数 g c d ( a , b ) gcd(a,b) gcd(a,b)

a , b , c a,b,c a,b,c 的最小公倍数 l c m ( l c m ( a , b ) , c ) lcm(lcm(a,b),c) lcm(lcm(a,b),c) (二者先求最小公倍数,结果与第三个数求最小公倍数)
a , b , c a,b,c a,b,c 的最大公因数 g c d ( g c d ( a , b ) , c ) gcd(gcd(a,b),c) gcd(gcd(a,b),c) (二者先求最大公因数,结果与第三个数求最大公因数)

l c m ( a , b ) = a × b / g c d ( a , b ) lcm(a,b)=a\times b /gcd(a,b) lcm(a,b)=a×b/gcd(a,b)

g c d ( l c m ( a , b ) , c ) = l c m ( g c d ( a , c ) , g c d ( b , c ) ) gcd(lcm(a,b),c)=lcm(gcd(a,c),gcd(b,c)) gcd(lcm(a,b),c)=lcm(gcd(a,c),gcd(b,c)) (该公式推导详见最大公因数与最小公倍数关系)

要点2:原题目S公式化简

(用a,b,c代替Ha,Hb,Hc)

S = a b c l c m ( a , b , c ) l c m ( a , b ) ⋅ l c m ( a , c ) ⋅ l c m ( b , c ) S=abc\frac{lcm(a,b,c)}{lcm(a,b)\cdot lcm(a,c)\cdot lcm(b,c)} S=abclcm(a,b)lcm(a,c)lcm(b,c)lcm(a,b,c)

= a b c l c m ( l c m ( a , b ) , c ) a b g c d ( a , b ) a c g c d ( a , c ) b c g c d ( b , c ) =abc\frac{lcm(lcm(a,b),c)}{\frac{ab}{gcd(a,b)}\frac{ac}{gcd(a,c)}\frac{bc}{gcd(b,c)}} =abcgcd(a,b)abgcd(a,c)acgcd(b,c)bclcm(lcm(a,b),c)

= a b c c l c m ( a , b ) g c d ( l c m ( a , b ) , c ) a b g c d ( a , b ) a c g c d ( a , c ) b c g c d ( b , c ) =abc\frac{\frac{clcm(a,b)}{gcd(lcm(a,b),c)}}{\frac{ab}{gcd(a,b)}\frac{ac}{gcd(a,c)}\frac{bc}{gcd(b,c)}} =abcgcd(a,b)abgcd(a,c)acgcd(b,c)bcgcd(lcm(a,b),c)clcm(a,b)

= c × l c m ( a , b ) g c d ( a , b ) g c d ( a , c ) g c d ( b , c ) a b c × g c d ( l c m ( a , b ) , c ) =\frac{c\times lcm(a,b)gcd(a,b)gcd(a,c)gcd(b,c)}{abc\times gcd(lcm(a,b),c)} =abc×gcd(lcm(a,b),c)c×lcm(a,b)gcd(a,b)gcd(a,c)gcd(b,c)

= l c m ( a , b ) g c d ( a , b ) g c d ( a , c ) g c d ( b , c ) a b × l c m ( g c d ( a , c ) , g c d ( b , c ) ) =\frac{lcm(a,b)gcd(a,b)gcd(a,c)gcd(b,c)}{ab\times lcm(gcd(a,c),gcd(b,c))} =ab×lcm(gcd(a,c),gcd(b,c))lcm(a,b)gcd(a,b)gcd(a,c)gcd(b,c)

= a b g c d ( a , b ) g c d ( a , b ) g c d ( a , c ) g c d ( b , c ) a b g c d ( a , c ) g c d ( b , c ) g c d ( g c d ( a , c ) , g c d ( b , c ) ) =\frac{\frac{ab}{gcd(a,b)}gcd(a,b)gcd(a,c)gcd(b,c)}{ab\frac{gcd(a,c)gcd(b,c)}{gcd(gcd(a,c),gcd(b,c))}} =abgcd(gcd(a,c),gcd(b,c))gcd(a,c)gcd(b,c)gcd(a,b)abgcd(a,b)gcd(a,c)gcd(b,c)

= g c d ( g c d ( a , c ) , g c d ( b , c ) ) =gcd(gcd(a,c),gcd(b,c)) =gcd(gcd(a,c),gcd(b,c))

= g c d ( a , b , c ) =gcd(a,b,c) =gcd(a,b,c)

即最终化简为 S = g c d ( a , b , c ) S=gcd(a,b,c) S=gcd(a,b,c),找出三个数使其的最大公因数最大

要点3:找到最大公因数最大的三个数

预处理,用cnt[i] 数组存储 i 值出现的次数,用vector v[i]存储i的倍数,
从大到小遍历每个数,当遇到第一个v[i] 中存储的倍数的个数大于等于3时,此时的 i 就是最大公因数。
将v[i]进行排序,则前三个数便是最大公因数i最大的三个数。

完整代码

#include 
#include 
#include 
using namespace std;

const int N = 1e5 + 10;  // 定义常量 N,表示闪亮度值的最大范围
int cnt[N];              // 定义数组 cnt,用于统计每个闪亮度值的出现次数
int n, m;                // n 表示宝石的数量,m 表示最大的闪亮度值
vector<int> v[N];        // 定义向量数组 v,用于存储每个因数的闪亮度值

int main() {
    // 输入宝石的数量 n
    scanf("%d", &n);

    // 输入每颗宝石的闪亮度值,并统计每个闪亮度值的出现次数
    for (int i = 0; i < n; i++) {
        int x;
        scanf("%d", &x);
        cnt[x]++;           // 统计闪亮度值 x 的出现次数
        m = max(m, x);      // 更新最大闪亮度值 m
    }

    // 对于每个可能的因数 i,收集所有能被 i 整除的闪亮度值
    for (int i = 1; i <= m; i++) {
        for (int j = i; j <= m; j += i) {
            if (cnt[j]) {    // 如果闪亮度值 j 存在
                for (int k = 0; k < cnt[j]; k++)
                    v[i].push_back(j);  // 将 j 添加到因数 i 的向量中
            }
        }
    }

    // 从最大的因数开始检查,找到第一个满足至少有 3 个闪亮度值的因数 i
    for (int i = m; i >= 1; i--) {
        if (v[i].size() >= 3) {  // 如果因数 i 的闪亮度值数量 >= 3
            sort(v[i].begin(), v[i].end());  // 对闪亮度值进行升序排序
            for (int j = 0; j < 3; j++) printf("%d ", v[i][j]);  // 输出最小的 3 个闪亮度值
            break;  // 找到后立即退出循环
        }
    }

    return 0;
}

你可能感兴趣的:(蓝桥杯,蓝桥杯,c语言,c++)