解题思路

题目要求找出一个最大的子集,使得其中任意两个数的和都不能被 整除。关键发现:

  1. 如果两个数的和能被 整除,那么它们对 的余数之和也能被 整除
  2. 对于余数为 的数,最多只能选一个
  3. 对于余数为 的数(当 为偶数时),最多只能选一个
  4. 对于其他余数 ,要在 中选择数量较多的那组

解题思路:

  1. 统计每个余数出现的次数
  2. 分类讨论:
    • 余数为0的情况
    • 为奇数时的情况
    • 为偶数时的情况

代码

#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 += 1

print(result)

算法及复杂度

  • 算法:余数定理 + 贪心
  • 时间复杂度: - 为数组长度,只需要遍历一次数组
  • 空间复杂度: - 需要一个大小为 的数组存储余数计数