2025.05.22-携程春招机考真题解析-第二题

📌 点击直达笔试专栏 👉《大厂笔试突围》

💻 春秋招笔试突围在线OJ 👉 笔试突围OJ

02. A先生的数组优化系统

问题描述

A先生负责一个数据处理系统,他需要对输入的数组进行优化处理。系统允许执行一种特殊的"协调操作":选择数组中的任意两个元素,将它们替换为两个新的正整数,但要求这两个新整数的最大公约数必须等于原来两个元素的最大公约数。

A先生的目标是通过多次协调操作,使得数组所有元素的总和达到最小值。他想知道,经过任意次优化操作后,数组元素总和的最小可能值是多少。

输入格式

第一行包含一个正整数 T T T 1 ≤ T ≤ 10 4 1 \leq T \leq 10^4 1T104),表示测试用例的数量。

对于每个测试用例:

  • 第一行包含一个正整数 n n n 1 ≤ n ≤ 2 × 10 5 1 \leq n \leq 2 \times 10^5 1n2×105),表示数组的长度。
  • 第二行包含 n n n 个正整数 a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1,a2,,an 1 ≤ a i ≤ 10 9 1 \leq a_i \leq 10^9 1ai109),表示数组的元素。

保证所有测试用例中 n n n 的总和不超过 2 × 10 5 2 \times 10^5 2×105

输出格式

对于每个测试用例,输出一行,包含一个整数,表示经过优化后能够得到的最小数组元素总和。

样例输入

2
2
1 2
3
3 7 9

样例输出

2
3
样例解释说明
样例1数组 [ 1 , 2 ] [1, 2] [1,2] 的最大公约数为 1 1 1,最小总和为 1 × 2 = 2 1 \times 2 = 2 1×2=2
样例2数组 [ 3 , 7 , 9 ] [3, 7, 9] [3,7,9] 的最大公约数为 1 1 1,可以通过协调操作将所有元素变为 1 1 1,最小总和为 1 × 3 = 3 1 \times 3 = 3 1×3=3

数据范围

  • 1 ≤ T ≤ 10 4 1 \leq T \leq 10^4 1T104
  • 1 ≤ n ≤ 2 × 10 5 1 \leq n \leq 2 \times 10^5 1n2×105
  • 1 ≤ a i ≤ 10 9 1 \leq a_i \leq 10^9 1ai109
  • 所有测试用例中 n n n 的总和不超过 2 × 10 5 2 \times 10^5 2×105

题解

这道题的关键insight是理解协调操作的本质。当我们选择两个元素 a i a_i ai a j a_j aj,将它们替换为 x x x y y y,且要求 gcd ⁡ ( x , y ) = gcd ⁡ ( a i , a j ) \gcd(x, y) = \gcd(a_i, a_j) gcd(x,y)=gcd(ai,aj) 时,我们可以选择 x = y = gcd ⁡ ( a i , a j ) x = y = \gcd(a_i, a_j) x=y=gcd(ai,aj)

通过多次这样的操作,我们可以将整个数组的所有元素都变成数组全体元素的最大公约数。具体分析:

  1. 任意两个元素都可以被替换为它们的最大公约数
  2. 通过连续的操作,所有元素最终都能变成整个数组的最大公约数
  3. 因此最小总和就是 n × gcd ⁡ ( a 1 , a 2 , … , a n ) n \times \gcd(a_1, a_2, \ldots, a_n) n×gcd(a1,a2,,an)

算法步骤:

  1. 计算数组所有元素的最大公约数
  2. 返回 n n n 乘以这个最大公约数

时间复杂度为 O ( n log ⁡ A ) O(n \log A) O(nlogA),其中 A A A 是数组元素的最大值。

参考代码

  • Python
import sys
import math
input = lambda: sys.stdin.readline().strip()

def gcd_list(arr):
    # 计算数组所有元素的最大公约数
    result = arr[0]
    for i in range(1, len(arr)):
        result = math.gcd(result, arr[i])
    return result

t = int(input())
for _ in range(t):
    n = int(input())
    arr = list(map(int, input().split()))
    
    # 计算最小总和
    g = gcd_list(arr)
    print(n * g)
  • Cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
using ll = long long;

ll gcd_func(ll a, ll b) {
    // 计算两个数的最大公约数
    return b == 0 ? a : gcd_func(b, a % b);
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        ll g;
        cin >> g;
        
        // 计算所有元素的最大公约数
        for (int i = 1; i < n; i++) {
            ll x;
            cin >> x;
            g = gcd_func(g, x);
        }
        
        cout << g * n << endl;
    }
    return 0;
}
  • Java
import java.util.Scanner;

public class Main {
    // 计算两个数的最大公约数
    private static long gcdFunc(long a, long b) {
        return b == 0 ? a : gcdFunc(b, a % b);
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        
        while (t-- > 0) {
            int n = sc.nextInt();
            long g = sc.nextLong();
            
            // 计算所有元素的最大公约数
            for (int i = 1; i < n; i++) {
                long x = sc.nextLong();
                g = gcdFunc(g, x);
            }
            
            System.out.println(g * n);
        }
        sc.close();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

春秋招笔试突围

你的鼓励是我最大的动力

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

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

打赏作者

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

抵扣说明:

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

余额充值