蓝桥杯 20. 倍数问题

倍数问题

原题目链接

题目描述

众所周知,小葱同学擅长计算,尤其擅长判断一个数是否是另一个数的倍数。但当面对多个数时,他就比较苦恼了。

现在小葱给了你 n 个数,希望你从中找出三个数,使得这三个数的 和是 K 的倍数,并且这个 和最大

题目保证一定存在解。

输入描述

  • 第一行包含两个正整数 nK
  • 第二行包含 n 个正整数,代表给定的数列。

数据范围:

  • 1 ≤ n ≤ 10⁵
  • 1 ≤ K ≤ 10³
  • 所有给定的整数不超过 10⁸

输出描述

输出一行一个整数,表示满足条件的最大和。

输入示例

4 3
1 2 3 4

输出示例

9

c++代码

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

int main() {
    ll n, K, x, a, b, c, ans = 0;
    cin >> n >> K;
    vector<vector<ll>> arr(K);
    for (ll i = 0; i < n; i++) cin >> x, arr[x % K].push_back(x);
    for (ll i = 0; i < K; i++) sort(arr[i].begin(), arr[i].end());
    for (ll i = 0; i < K; i++) {
        if (arr[i].size() <= 0) continue;
        a = arr[i].back(), arr[i].pop_back();
        for (ll j = i; j < K; j++) {
            if (arr[j].size() <= 0) continue;
            b = arr[j].back(), arr[j].pop_back();
            ll val = K - i - j;
            while(val < 0) val += K;
            while(val <= K - 1) {
                if (arr[val].size() > 0) c = arr[val].back(), ans = max(ans, a + b + c);
                val += K;
            }
            arr[j].push_back(b);
        }
        arr[i].push_back(a);
    }
    cout << ans;
    return 0;
}//by wqs

题目解析

给你 n 个数和一个整数 K,从这 n 个数中选出三个数 a, b, c,要求:

  • (a + b + c) % K == 0
  • a + b + c 最大化

假设(a + b + c) % K = 0,

那么(a % K + b % K + c % K) % K = 0,

假设a % K = d, b % K = e,

根据(d+ e + c % K) % K = 0,并且数据的值都是正数

也就是说d + e + c % K = n * K(n >= 1),

也就是说c % K = n * K - d - e

那么c % K = K - d - e 或者 2 * K - d - e或者3 * K - d - e…

不要认为有很多种情况,我们看看c % K的范围,

显然,0 <= c % K <= K - 1,

也就是0 <= n * K - d - e <= K - 1,

可见在这个范围下不会有多少种情况,因为K的最大值才1000。

算法流程

枚举两个数的余数,然后计算第三个数所需的余数,根据贪心算法并在对应余数组中取最大值

1. 分类存储:

将所有数字按其对 K 取模的结果分成 K 个桶,即: arr[i] 存放所有 x 满足 x % K == i

这样做的目的,是为了快速找出所有具有相同模值的数,为后续组合提供便利。

2. 排序每个桶:

为了后续能快速取出某个模值的最大值,对每个桶排序,这样能轻松获取每个模值中最大的元素

3. 枚举前两个数模值 (i, j)

你遍历所有 i, j ∈ [0, K),对每一组 (i, j)

  • arr[i] 取最大值 a
  • arr[j] 取最大值 b

4. 根据前两个快速得出第三个模值k:

k = n * K - i - j(n >= 1, 0 <= k <= K - 1)

5. 特别处理下标冲突:

你保存了桶中最大的数后还要回填,因为之后还会用到这些桶。每次取出最大值后记得放回去。

### 关于蓝桥杯竞赛中Python相关的倍数问题 #### 解题思路 对于涉及倍数问题,在编程竞赛尤其是像蓝桥杯这样的赛事里,通常会围绕着整除特性展开。这类题目可能要求找出一定范围内的某个特定数字的倍数或者是处理多个数值之间的最小公倍数问题。 当面对具体的倍数查找任务时,一种常见的策略是从给定范围内遍历每一个潜在候选者,并通过取余操作来验证其是否满足条件[^2]。如果目的是找到一系列连续自然数中的某固定正整数\(n\)的所有倍数,则可以通过循环结构实现这一逻辑;而对于更复杂的场景比如求解两数间的最小公倍数(LCM),则往往先要确定这两个数的最大公约数(GCD)[^4],再基于两者关系\[LCM(a,b)=\frac{|a*b|}{GCD(a,b)}\]完成计算。 针对蓝桥杯的具体实例而言,假设存在一道关于寻找指定区间内能被若干个预设基数整除的元素集合的任务,那么解决方案应当考虑: - 明确输入数据的形式与约束; - 设计高效的算法以减少不必要的迭代次数; - 利用数学原理优化性能表现,例如提前终止搜索路径或是跳过不可能符合条件的情况。 #### 示例代码 下面给出一段用于检测并打印出0至100之间所有能够同时被3和5整除(即既是3又是5的倍数)的Python程序片段作为例子: ```python def find_multiples(start, end, divisors): result = [] for i in range(start, end + 1): if all(i % d == 0 for d in divisors): # Check divisibility by each divisor result.append(i) return result if __name__ == "__main__": multiples_of_3_and_5 = find_multiples(0, 100, [3, 5]) print(multiples_of_3_and_5) ``` 这段代码定义了一个名为`find_multiples()`的功能函数,它接受起始值、结束值以及一组除数列表作为参数,返回该区间内可被这些除数全部整除的结果集。最后部分展示了如何调用此功能并输出结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值