給定一個由n個不同integer所成之集合S,
印出最大的子集合S',當中S'必須符合以下條件:
S'中任意2元素之和無法被k所整除。
輸入:
第一行分別給入n, k,用空格隔開。
第二行給入n個數字,代表這個集合的所有元素。
輸出:
印出符合前述之最大可能的子集合S'的大小。
範例輸入:
4 3
1 7 2 4
輸出則為3
解題:
思路請參照
http://cs.stackexchange.com/questions/57873/maximum-subset-pairwise-not-divisible-by-k
簡單來說,2個數的和能被k整除的話,
代表它們除以k的餘數和也能被k整除(同餘定理)。
舉例來說:
a = bk + c, d = ek + f
a+d = k(b+d) + c+f
前項當然能被k整除,那麼a+d能不能被k整除,
就要看c+f能不能被k整除。
知道這點的話,那麼除以k的餘數可能為0~k-1,
我們可以先分類記錄成一個陣列,
用來表示除以k的餘數為s_i的話,
num[s_i]有幾個。
當k是奇數的時候,兩個數要加起來能被k整除的話,
必然是一個比k/2小,一個比k/2大。
於是遍歷從1到比k/2小的整數,
for(int i = 1; i < k/2; i++)
檢查是num[i]比較大呢,還是num[k-i]比較大呢?
因為兩個互斥,我們就取比較大的放入S'中。
接著留意k是偶數的時候,由於餘數是k/2的話,
兩個一配起來就可以被k整除了,
所以在num[k/2]>0的狀況仍然只能取1個進S'中。
同樣的,餘數是0的狀況下也只能取1個進S'中。
由於在計算時k/2比較特殊,下面的code中有特別分開來計算,
請參閱下方的code。
另外特殊的case為n只有1個或k剛好是1的狀況,
這時候就只能取1個了!
這題在從頭仔細思考過一遍以後,
其實並不算太過複雜,
根本核心在於同餘的概念,
以及如何處理k/2的case。
難怪雖然是Easy Level,答對率卻並不是太高。
Code:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main() {
int n, k, result=0;
scanf("%d %d",&n, &k);
// Special case: 1. integer num only 1 -> result = 1;
// 2. divisor k = 1 -> result = 1
if(n == 1 || k == 1){
printf("%d", 1);
}else{
int s_i, num[k];
for(int i = 0; i < k; i++)
num[i] = 0;
// Store num of those whose remainder is k' at num[k'].
for(int arr_i = 0; arr_i < n; arr_i++){
scanf("%d",&s_i);
s_i %= k;
num[s_i] += 1;
}
for(int i = 1; i < k/2; i++){
if(num[i] > num[k-i])
result += num[i];
else
result += num[k-i];
}
if(num[0] > 0) result++;
if(k % 2 == 0){
if(num[k/2] > 0)
result++;
}else{
if(num[k/2] > num[k/2 + 1])
result += num[k/2];
else
result += num[k/2 +1];
}
printf("%d", result);
}
return 0;
}
沒有留言:
張貼留言