题目
题目链接
解题思路
题目要求找出一个最大的子集,使得其中任意两个数的和都不能被 \(K\) 整除。关键发现:
- 如果两个数的和能被 \(K\) 整除,那么它们对 \(K\) 的余数之和也能被 \(K\) 整除
- 对于余数为 \(0\) 的数,最多只能选一个
- 对于余数为 \(K/2\) 的数(当 \(K\) 为偶数时),最多只能选一个
- 对于其他余数 \(i\),要在 \(i\) 和 \(K-i\) 中选择数量较多的那组
解题思路:
- 统计每个余数出现的次数
- 分类讨论:
- 余数为0的情况
- \(K\) 为奇数时的情况
- \(K\) 为偶数时的情况
代码
#include <iostream>
#include <vector>
using namespace std;int main() {int N, K;cin >> N >> K;// 读取数组并统计余数vector<int> remainderCount(K);for (int i = 0; i < N; i++) {int num;cin >> num;remainderCount[num % K]++;}// 计算最大子集大小int result = 0;// 处理余数为0的情况if (remainderCount[0] > 0) {result++;}// 处理其他余数if (K % 2 == 1) {// K为奇数for (int i = 1; i <= (K-1)/2; i++) {result += max(remainderCount[i], remainderCount[K-i]);}} else {// K为偶数for (int i = 1; i < K/2; i++) {result += max(remainderCount[i], remainderCount[K-i]);}// 处理K/2的情况if (remainderCount[K/2] > 0) {result++;}}cout << result << endl;return 0;
}
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int N = sc.nextInt();int K = sc.nextInt();// 统计余数出现次数int[] remainderCount = new int[K];for (int i = 0; i < N; i++) {int num = sc.nextInt();remainderCount[num % K]++;}// 计算最大子集大小int result = 0;// 处理余数为0的情况if (remainderCount[0] > 0) {result++;}// 处理其他余数if (K % 2 == 1) {// K为奇数for (int i = 1; i <= (K-1)/2; i++) {result += Math.max(remainderCount[i], remainderCount[K-i]);}} else {// K为偶数for (int i = 1; i < K/2; i++) {result += Math.max(remainderCount[i], remainderCount[K-i]);}// 处理K/2的情况if (remainderCount[K/2] > 0) {result++;}}System.out.println(result);}
}
# 读取输入
N, K = map(int, input().split())
nums = list(map(int, input().split()))# 统计余数出现次数
remainder_count = [0] * K
for num in nums:remainder_count[num % K] += 1# 计算最大子集大小
result = 0# 处理余数为0的情况
if remainder_count[0] > 0:result += 1# 处理其他余数
if K % 2 == 1:# K为奇数for i in range(1, (K-1)//2 + 1):result += max(remainder_count[i], remainder_count[K-i])
else:# K为偶数for i in range(1, K//2):result += max(remainder_count[i], remainder_count[K-i])# 处理K/2的情况if remainder_count[K//2] > 0:result += 1print(result)
算法及复杂度
- 算法:余数定理 + 贪心
- 时间复杂度:\(\mathcal{O}(n)\) - \(n\) 为数组长度,只需要遍历一次数组
- 空间复杂度:\(\mathcal{O}(K)\) - 需要一个大小为 \(K\) 的数组存储余数计数