答题实践笔记
题目解析
问题描述
小M有块巧克力板,每块巧克力的边长为,重量为。她有个背包,每个背包有一个最大承重限制。对于每个背包,她想知道在不超过背包承重的情况下,最多能带走多少块巧克力板。
思路分析
-
计算每块巧克力的重量:由于每块巧克力的重量为其边长的平方,我们需要先计算出所有巧克力的重量。
-
排序巧克力重量:将巧克力的重量从小到大排序,这样可以确保我们优先选择重量较轻的巧克力,从而在背包容量有限的情况下带走更多的巧克力。
-
前缀和计算:计算排序后巧克力重量的前缀和。前缀和数组中的第个元素表示前块最轻巧克力的总重量。
-
处理查询:对于每个背包的承重限制,我们可以使用二分查找(如
upper_bound函数)在前缀和数组中找到不超过背包承重的最大巧克力数量。
图解
上图展示了巧克力重量的累积和与背包承重的关系。通过找到背包承重在累积重量曲线上的位置,可以确定最多能带走的巧克力数量。
代码详解
vector<int> solution(int n, int m, vector<int> a, vector<int> queries) {
// 计算每块巧克力的重量
vector<long long> weights(n);
for(int i = 0; i < n; ++i) {
weights[i] = (long long)a[i] * a[i];
}
// 将重量排序
sort(weights.begin(), weights.end());
// 计算前缀和
vector<long long> prefix_sums(n);
prefix_sums[0] = weights[0];
for(int i = 1; i < n; ++i) {
prefix_sums[i] = prefix_sums[i-1] + weights[i];
}
// 处理每个查询
vector<int> result;
for(int i = 0; i < m; ++i) {
long long capacity = queries[i];
// 使用upper_bound找到第一个前缀和大于背包承重的位置
int count = upper_bound(prefix_sums.begin(), prefix_sums.end(), capacity) - prefix_sums.begin();
result.push_back(count);
}
return result;
}
关键步骤说明:
- weights计算:为了避免整数溢出,将乘积转换为
long long类型。 - 排序:
sort函数对巧克力重量进行排序,确保从最轻的开始选择。 - 前缀和计算:通过累加前面的重量,得到当前能携带的总重量。
- upper_bound使用:
upper_bound函数在有序数组中查找第一个大于目标值的位置,这个位置的索引即为最多能携带的巧克力数量。
知识总结
二分查找与upper_bound
- 二分查找:在有序数组中快速查找目标值的位置,时间复杂度为。
- upper_bound:C++ STL中的函数,用于在有序序列中查找第一个大于给定值的位置。
学习建议:对于算法竞赛和实际开发,熟练掌握STL库中的算法函数能够大大提高编码效率和代码性能。建议初学者多练习二分查找的变体和应用。
前缀和技巧
- 前缀和:通过预处理数组,使得在时间内计算任意区间的累加和。
- 应用场景:适用于需要频繁计算区间和的问题。
学习建议:前缀和是基础且高效的算法技巧,熟练掌握后可以解决很多数组和序列相关的问题。
学习计划
制定刷题计划
- 明确目标:根据自己的水平和目标(如参加竞赛、面试等)制定合适的计划。
- 分配时间:每天固定时间练习,保持连续性。
- 分级练习:从简单题目开始,逐步挑战更高难度的题目。
利用错题进行针对性学习
- 记录错题:建立错题本,记录每次做错的题目和错误原因。
- 定期复习:定期回顾错题,巩固知识点。
- 深入思考:对于不理解的题目,查阅资料或请教他人,直到彻底明白。
高效学习方法:
- 主动思考:在看答案前,尽量自己思考解决方案。
- 代码调试:多调试代码,理解每一行代码的作用。
- 总结归纳:做完一类题目后,进行总结,找出通用的解题方法。
工具运用
结合AI与学习资源
- 利用AI辅助:使用如ChatGPT等AI工具,帮助理解复杂的概念或代码。
- 在线题库:结合LeetCode、牛客网等在线题库,进行系统性的练习。
- 教学视频:观看算法教学视频,加深对算法思想的理解。
总结
通过这次题目的练习,我们不仅巩固了二分查找和前缀和的知识,还学会了如何高效地处理批量查询的问题。在学习过程中,善于利用各种工具和资源,能够事半功倍。希望这些经验对其他同学也有所帮助。 #青训营笔记创作活动