给定一个由正整数组成的集合S,找出一个最大的子集合S,使得S中任意两个数字的和都不能被K整除。
例如S=「10,10,12,19,22,24,25」,K=4。此时S最多只能取3个数,可能的取值为「10,12,25」或者「19,22,24」等。
输入为两行,第一行两个数字,分别表示集合S的元素数量N和K。第二行为N个数字,分别是S的各个元素值。
数据范围:
1 < N < 10^5
1 < K < 100
1 < S[i] < 10^9
输出为一个数字,集合S的最大长度。
4 3 1 7 2 4
3
//K范围很小啊,直接求余数哈希,特别注意处理一下余数为0,以及K为偶数时余数为K/2的情况即可。
#include<iostream>
using namespace std;
int main() {
int N, K;
cin>>N>>K;
int rec[K];
long long tmp;
int res = 0;
for(int i = 0; i < K; i++) {
rec[i] = 0;
}
for(int i = 0; i < N; i++) {
cin>>tmp;
rec[tmp%K]++;
}
if(rec[0] > 0) {
res = 1;
}
if(K%2 == 0) {
for(int i = 1; i <= K/2-1; i++) {
res = res + max(rec[i], rec[K-i]);
}
if(rec[K/2] > 0) {
res++;
}
}
else {
for(int i = 1; i <= K/2; i++) {
res = res + max(rec[i], rec[K-i]);
}
}
cout<<res<<endl;
return 0;
} #include <bits/stdc++.h>
using namespace std;
int main(){
int n,k,x;
cin>>n>>k;
int a[k];
memset(a,0,sizeof(a));
for(int i=0;i<n;i++){
cin>>x;
a[x%k]++;
}
int s = a[0]>0?1:0;
for(int i=1,j=k-1;i<=j;i++,j--)
s += (i==j)?(a[i]>0?1:0):max(a[i],a[j]);
cout<<s<<endl;
return 0;
} import java.util.*;
public class Main {
// 子集合中任意两数之和不能被k整除
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while (in.hasNext()) {
int n = in.nextInt(), k = in.nextInt();
long[] arr = new long[n];
for (int i = 0; i < n; i++) {
arr[i] = in.nextLong();
}
fun(arr, k);
}
}
// 动态规划处理
public static void fun(long[] arr, int k) {
int n = arr.length;
Node[] dp = new Node[n];
for (int i = 0; i < n; i++) { // base case
dp[i] = new Node();
if (arr[i] % k != 0) {
dp[i].size = 1;
dp[i].list.add(arr[i]);
}
}
int max = 0; // 最大长度
for (int i = 1; i < n; i++) {
int idx = -1; // 记录最大下标
for (int j = 0; j < i; j++) {
if ((arr[i] + arr[j]) % k != 0) { // 存在
boolean flag = true;
for (long l : dp[j].list) { // 观察每一个是否可行
if ((arr[i] + l) % k == 0) {
flag = false;
break;
}
}
if (flag) { // 都相安无事就更新
if (dp[j].size + 1 > dp[i].size) {
dp[i].size = dp[j].size + 1;
idx = j;
}
}
}
}
if (idx != -1) { // 找到了可以加入的集合
dp[i].size = dp[idx].size + 1;
dp[i].list = dp[idx].list;
dp[i].list.add(arr[i]);
max = Math.max(max, dp[i].size);
}
}
System.out.println(max);
}
}
// 结点的定义
class Node {
int size;
ArrayList<Long> list;
public Node() {
size = 0;
list = new ArrayList<>();
}
}
a=list(map(int,input().split())) if len(a)<2: l=a k=int(input()) else: l=a[0] k=a[1] arr=list(map(int,input().split())) arr_1=[i%k for i in arr] count_n=0 for i in range(0,k): if i in arr_1: if i==0: count_n+=1 elif i ==k/2: count_n+=1 else: num_i=0 for j in arr_1: if j==i: num_i+=1 if k-i in arr_1: num_k_i=0 for p in arr_1: if p==k-i: num_k_i+=1 count_n+=max(num_i,num_k_i) arr_1.remove(k-i) else: count_n+=num_i arr_1.remove(i) print(count_n)
package main
import (
"fmt"
)
/*
1,感觉是这是一个数学问题,和数据结构没什么关系,开始是想用回溯组合求值,但是后来发现了其中的数学规律。
题目说 任意两个数字的和都不能被K整除, 也就是这两个任意数之和 对K模运算取余数 不能整除 K 。这里调一下计算顺序。,先取模,并记录次数。
1.1 将 N个数 对 K 取余 ,将余数和对应出现的次数放入 Map中。
1.2 [0, 1, 2, 3, .... , K-1] 是 Map 中可能存在的键值。将这些键值从中间分为两份,因为 中间堆成,比如 1 和 K-1 不能同时出现,哪一个出现的次数多就取哪一个
1.3 处理边界条件, K 为 偶数, K/2 最多能出现依次, K为奇数,比较 K/2 和 K-K/2 那个次数出现的多。
1.4 还有一个边界条件,0 最多出现一次
*/
var SMap map[int]int
func main(){
var N,K, t int
fmt.Scanf("%d",&N)
fmt.Scanf("%d",&K)
SMap := make(map[int]int)
for i:=0;i<N;i++{
fmt.Scanf("%d",&t)
SMap[t%K] = SMap[t%K]+1
}
sum := 0
if SMap[0] > 0 { // 边界为 0 的情况,最多只能出现一次
sum = 1
}
for i := 1; i < K/2 ; i++ {
sum += Max(SMap[i], SMap[K-i]) // 对称比较, i 和 K-i 不能同时现在结果中。
}
if K%2 == 0 { // 边界条件, 处理 K 的奇偶情况
if SMap[K/2] > 0 { // K/2 = K-K/2
sum += 1
}
} else {
sum += Max(SMap[K/2], SMap[K-K/2]) // K/2 != K-K/2
}
fmt.Println(sum)
}
func Max(a, b int) int {
if a > b {
return a
} else {
return b
}
} def solve(nums, n, k): numcnt = [0 for i in range(k)] for num in nums: numcnt[num % k] += 1 count = 0 count += min(1, numcnt[0]) # 0 if k & 0x01: # 奇数 for i in range(1, k // 2 + 1): count += max(numcnt[i], numcnt[k - i]) else: # 偶数 count += min(1, numcnt[k // 2]) # k / 2 for i in range(1, k // 2): count += max(numcnt[i], numcnt[k - i]) return count getNumsFromString = lambda x: list(map(int, x.strip().split())) n, k = getNumsFromString(input()) nums = getNumsFromString(input()) print(solve(nums, n, k))
class Solution {
public:
long hanWuJi_JiHeYuanSuBuNengZhengchu(vector<int> S, int K)
{
for (auto iteri = S.begin(); iteri != S.end(); iteri++)
{
for (auto iterj = iteri+1; iterj != S.end(); )
{
if ((*iteri + *iterj) % K == 0)
{
iterj=S.erase(iterj);
}
else iterj++;
}
}
return S.size();
}
}; ## 为啥只能过80%??? N, K = list(map(int, input().split())) nums = list(map(int, input().split())) arr = [0 for _ in range(K)] for it in nums: arr[it%K] += 1 tSum = 0 if arr[0] >= 1: tSum = 1 i, j = 1, K-1 while i <= j: if i == j and arr[i] >= 1: tSum += 1 else: tSum += max(arr[i], arr[j]) i+=1 j-=1 print(tSum)
#include<iostream>
using namespace std;
int main()
{
int n,k,a[10001],i,num[101]={0},ke,max=0;
cin>>n>>k;
for(i=1;i<=n;i++){cin>>a[i];a[i]=a[i]%k;num[a[i]]++;}//取余数,统计一下
if(k%2==0){ke=k/2-1;if(num[k/2])max=1;}//k/2是整数的话处理一下
else ke=k/2;
if(num[0])max++;//余数为0的只能有一个
for(i=1;i<=ke;i++)
if(num[i]>num[k-i])max=max+num[i];
else max=max+num[k-i];//i和k-i哪个多就加哪个
cout<<max;
return 0;
} def long_set(num,k):
if not num:
return 0
if k==1 or len(num)==1:
return 1
dic = {}
for i in num:
tem = i%k
dic[tem] = dic.get(tem,0)+1
dp = [0 for _ in range(k)]
for i in list(dic.items()):
dp[i[0]] = i[1]
res = min(1,dp[0])
if k&1==1:
j = 1
while j <= k//2:
res += max(dp[j],dp[k-j])
j += 1
else:
m = 1
while m<k//2:
res += max(dp[m],dp[k-m])
m += 1
res += min(1,dp[m])
return res
if __name__=='__main__':
n,k = list(map(int,input().split()))
num = list(map(int,input().split()))
print(long_set(num,k))