文章目录
- 周赛363
- [2859. 计算 K 置位下标对应元素的和](https://leetcode.cn/problems/sum-of-values-at-indices-with-k-set-bits/)
- 模拟
- [2860. 让所有学生保持开心的分组方法数](https://leetcode.cn/problems/happy-students/)
- 排序 + 枚举
- [2861. 最大合金数](https://leetcode.cn/problems/maximum-number-of-alloys/)
- 二分答案
- [2862. 完全子集的最大元素和](https://leetcode.cn/problems/maximum-element-sum-of-a-complete-subset-of-indices/)
- 数学
周赛363
2859. 计算 K 置位下标对应元素的和
简单
给你一个下标从 0 开始的整数数组 nums
和一个整数 k
。
请你用整数形式返回 nums
中的特定元素之 和 ,这些特定元素满足:其对应下标的二进制表示中恰存在 k
个置位。
整数的二进制表示中的 1 就是这个整数的 置位 。
例如,21
的二进制表示为 10101
,其中有 3
个置位。
示例 1:
输入:nums = [5,10,1,5,2], k = 1
输出:13
解释:下标的二进制表示是:
0 = 0002
1 = 0012
2 = 0102
3 = 0112
4 = 1002
下标 1、2 和 4 在其二进制表示中都存在 k = 1 个置位。
因此,答案为 nums[1] + nums[2] + nums[4] = 13 。
示例 2:
输入:nums = [4,3,2,1], k = 2
输出:1
解释:下标的二进制表示是:
0 = 002
1 = 012
2 = 102
3 = 112
只有下标 3 的二进制表示中存在 k = 2 个置位。
因此,答案为 nums[3] = 1 。
提示:
1 <= nums.length <= 1000
1 <= nums[i] <= 105
0 <= k <= 10
模拟
class Solution {public int sumIndicesWithKSetBits(List<Integer> nums, int k) {int cnt = 0;for(int i = 0; i < nums.size(); i++){if(Integer.bitCount(i) == k)cnt += nums.get(i);}return cnt;}
}
2860. 让所有学生保持开心的分组方法数
中等
给你一个下标从 0 开始、长度为 n
的整数数组 nums
,其中 n
是班级中学生的总数。班主任希望能够在让所有学生保持开心的情况下选出一组学生:
如果能够满足下述两个条件之一,则认为第 i
位学生将会保持开心:
- 这位学生被选中,并且被选中的学生人数 严格大于
nums[i]
。 - 这位学生没有被选中,并且被选中的学生人数 严格小于
nums[i]
。
返回能够满足让所有学生保持开心的分组方法的数目。
示例 1:
输入:nums = [1,1]
输出:2
解释:
有两种可行的方法:
班主任没有选中学生。
班主任选中所有学生形成一组。
如果班主任仅选中一个学生来完成分组,那么两个学生都无法保持开心。因此,仅存在两种可行的方法。
示例 2:
输入:nums = [6,0,3,3,6,7,2,7]
输出:3
解释:
存在三种可行的方法:
班主任选中下标为 1 的学生形成一组。
班主任选中下标为 1、2、3、6 的学生形成一组。
班主任选中所有学生形成一组。
提示:
1 <= nums.length <= 105
0 <= nums[i] < nums.length
排序 + 枚举
https://leetcode.cn/problems/happy-students/solutions/2446022/pai-xu-pythonjavacgojs-by-endlesscheng-ptzl/
class Solution {public int countWays(List<Integer> nums) {int[] a = nums.stream().mapToInt(i -> i).toArray();Arrays.sort(a);int n = a.length;int ans = a[0] > 0 ? 1 : 0; // 一个学生都不选的情况for(int i = 0; i < n-1; i++){if(a[i] < i+1 && i+1 < a[i+1])ans++;}return ans + 1; // +1 是因为可以都选}
}
2861. 最大合金数
中等
假设你是一家合金制造公司的老板,你的公司使用多种金属来制造合金。现在共有 n
种不同类型的金属可以使用,并且你可以使用 k
台机器来制造合金。每台机器都需要特定数量的每种金属来创建合金。
对于第 i
台机器而言,创建合金需要 composition[i][j]
份 j
类型金属。最初,你拥有 stock[i]
份 i
类型金属,而每购入一份 i
类型金属需要花费 cost[i]
的金钱。
给你整数 n
、k
、budget
,下标从 1 开始的二维数组 composition
,两个下标从 1 开始的数组 stock
和 cost
,请你在预算不超过 budget
金钱的前提下,最大化 公司制造合金的数量。
所有合金都需要由同一台机器制造。
返回公司可以制造的最大合金数。
示例 1:
输入:n = 3, k = 2, budget = 15, composition = [[1,1,1],[1,1,10]], stock = [0,0,0], cost = [1,2,3]
输出:2
解释:最优的方法是使用第 1 台机器来制造合金。
要想制造 2 份合金,我们需要购买:
- 2 份第 1 类金属。
- 2 份第 2 类金属。
- 2 份第 3 类金属。
总共需要 2 * 1 + 2 * 2 + 2 * 3 = 12 的金钱,小于等于预算 15 。
注意,我们最开始时候没有任何一类金属,所以必须买齐所有需要的金属。
可以证明在示例条件下最多可以制造 2 份合金。
示例 2:
输入:n = 3, k = 2, budget = 15, composition = [[1,1,1],[1,1,10]], stock = [0,0,100], cost = [1,2,3]
输出:5
解释:最优的方法是使用第 2 台机器来制造合金。
要想制造 5 份合金,我们需要购买:
- 5 份第 1 类金属。
- 5 份第 2 类金属。
- 0 份第 3 类金属。
总共需要 5 * 1 + 5 * 2 + 0 * 3 = 15 的金钱,小于等于预算 15 。
可以证明在示例条件下最多可以制造 5 份合金。
示例 3:
输入:n = 2, k = 3, budget = 10, composition = [[2,1],[1,2],[1,1]], stock = [1,1], cost = [5,5]
输出:2
解释:最优的方法是使用第 3 台机器来制造合金。
要想制造 2 份合金,我们需要购买:
- 1 份第 1 类金属。
- 1 份第 2 类金属。
总共需要 1 * 5 + 1 * 5 = 10 的金钱,小于等于预算 10 。
可以证明在示例条件下最多可以制造 2 份合金。
提示:
1 <= n, k <= 100
0 <= budget <= 108
composition.length == k
composition[i].length == n
1 <= composition[i][j] <= 100
stock.length == cost.length == n
0 <= stock[i] <= 108
1 <= cost[i] <= 100
二分答案
https://leetcode.cn/problems/maximum-number-of-alloys/solutions/2446024/er-fen-da-an-fu-ti-dan-by-endlesscheng-3jdr/
class Solution {// 挨个判断每台机器最多可以制造多少份合金。public int maxNumberOfAlloys(int n, int k, int budget, List<List<Integer>> composition, List<Integer> Stock, List<Integer> Cost) {int ans = 0;int mx = Collections.min(Stock) + budget;int[] stock = Stock.stream().mapToInt(i -> i).toArray();int[] cost = Cost.stream().mapToInt(i -> i).toArray();for(List<Integer> Com : composition){int[] com = Com.stream().mapToInt(i -> i).toArray();int left = 0, right = mx + 1;while(left < right){int mid = (left + right + 1) >> 1;boolean ok = true;long money = 0;// 计算一下用 i 机器能否达到要求for(int i = 0; i < n; i++){if(stock[i] < (long) com[i] * mid){money += ((long) com[i] * mid - stock[i]) * cost[i];if(money > budget){ok = false;break;}}}if(!ok){right = mid - 1;}else{left = mid;}}ans = Math.max(ans, right);}return ans;}
}
2862. 完全子集的最大元素和
困难
给你一个下标从 1 开始、由 n
个整数组成的数组。
如果一组数字中每对元素的乘积都是一个完全平方数,则称这组数字是一个 完全集 。
下标集 {1, 2, ..., n}
的子集可以表示为 {i1, i2, ..., ik}
,我们定义对应该子集的 元素和 为 nums[i1] + nums[i2] + ... + nums[ik]
。
返回下标集 {1, 2, ..., n}
的 完全子集 所能取到的 最大元素和 。
完全平方数是指可以表示为一个整数和其自身相乘的数。
示例 1:
输入:nums = [8,7,3,5,7,2,4,9]
输出:16
解释:除了由单个下标组成的子集之外,还有两个下标集的完全子集:{1,4} 和 {2,8} 。
与下标 1 和 4 对应的元素和等于 nums[1] + nums[4] = 8 + 5 = 13 。
与下标 2 和 8 对应的元素和等于 nums[2] + nums[8] = 7 + 9 = 16 。
因此,下标集的完全子集可以取到的最大元素和为 16 。
示例 2:
输入:nums = [5,10,3,10,1,13,7,9,4]
输出:19
解释:除了由单个下标组成的子集之外,还有四个下标集的完全子集:{1,4}、{1,9}、{2,8}、{4,9} 和 {1,4,9} 。
与下标 1 和 4 对应的元素和等于 nums[1] + nums[4] = 5 + 10 = 15 。
与下标 1 和 9 对应的元素和等于 nums[1] + nums[9] = 5 + 4 = 9 。
与下标 2 和 8 对应的元素和等于 nums[2] + nums[8] = 10 + 9 = 19 。
与下标 4 和 9 对应的元素和等于 nums[4] + nums[9] = 10 + 4 = 14 。
与下标 1、4 和 9 对应的元素和等于 nums[1] + nums[4] + nums[9] = 5 + 10 + 4 = 19 。
因此,下标集的完全子集可以取到的最大元素和为 19 。
提示:
1 <= n == nums.length <= 104
1 <= nums[i] <= 109
数学
class Solution {/**定义 core(n) 为 n 去处完全平方因子后的剩余结果若同一组有两个数,它们的下标的core值不同,那么这两个数相乘,就不是一个完全平方数所以 同一组的数字下标的core值必须都一样按照下标的core值分组,累加同一组的元素和,最大元素和即为答案*/public long maximumSum(List<Integer> nums) {long ans = 0;int n = nums.size();long[] sum = new long[n+1];for(int i = 0; i < nums.size(); i++){int c = core(i + 1);sum[c] += nums.get(i);ans = Math.max(ans, sum[c]);}return ans;}// 质因数分解,core(n) 为 n 去处完全平方因子后的剩余结果private int core(int n) {int res = 1;for (int i = 2; i * i <= n; i++) {int e = 0;while (n % i == 0) {e ^= 1;n /= i;}if (e == 1) {res *= i;}}if (n > 1) {res *= n;}return res;}
}