# SubArray ## Problem Given an array of $n$ distinct integers, print the size of a maximal subarray of $S$ where the sum of any $2$ numbers in $S'$ is not evenly divisible by $k$. ### Input format - The first line contains 2 space-separated integers $n$ and $k$, the number of values in $S$ and the non factor. - The second line contains $n$ space-separated integers $a_1, a_2, ..., a_n$, which are the values of array $S$. Each $a_i$ is the unique value of the array. ### Output format - Only one intergers, which is the length of subarray. ### Constraints - $1 \leq n \leq 10^5$ - $1 \leq k \leq 100$ - $1 \leq a_i \leq 10^9$ - All of the given numbers in array are distinct. ### Example ``` Input: 4 3 1 7 2 4 Output: 3 ``` **Explanation:** The sums of all permutations of two elements from $S$: ``` 1 + 7 = 8 1 + 2 = 3 (divisible by k) 1 + 4 = 5 7 + 2 = 9 (divisible by k) 7 + 4 = 11 2 + 4 = 6 (divisible by k) ``` Only $S' = [1, 7, 4]$ is accepted ## Tutorial ### Greedy solution #### Giải thích thuật toán Với mỗi số trong dãy số $a$, ta thực hiện push dần các số vào một set kết quả(gọi là $ans$). Với các mỗi số (gọi là $v$) phải kiểm tra xem là các số trong $ans$ có thích hợp hay không, nói cách khác là có tồn tại giá trị $u$ trong $ans$ sao cho $(u+v)$ có chia hết cho $k$ hay không. Nếu có tồn tại thì có nghĩa $v$ không phù hợp. ``` ans = [] for v in (các số trong dãy a): if (tồn tại u in ans) and (u+v) mod k = 0: giá trị v không thích hợp else: v -> ans kết quả là len(ans) ``` **Nhận xét**: Đây là một cách giải theo hướng greedy nên sẽ không đảm bảo kết quả sẽ đúng. #### Độ phức tạp $O(n*n)$ (worst case) #### Code ```c #include <bits/stdc++.h> #define MAXN 100005 using namespace std; int a[MAXN]; bool check(vector <int> arr, int val, int k){ for(int u: arr) if((u+val) % k == 0) return false; return true; } int main(){ int n, k; cin >> n >> k; for(int i = 0; i < n; i++) cin >> a[i]; vector <int> arr; for(int i = 0; i < n; i++){ if(check(arr, a[i], k)) arr.push_back(a[i]); } cout << arr.size() << '\n'; } ``` ### Accepted solution #### Giải thích thuật toán Nhận thấy: $(x + y) \bmod k = ((x \bmod k) + (y \bmod k)) \bmod k$. Từ đó ta có thể biến đổi dãy số $a$ như sau $a_i = a_i \bmod k$, như vậy các số chỉ dao động từ $[0, k-1]$. Do các số chỉ nằm trong $[0, k-1]$ nên những cặp tổng chia hết cho $k$ sẽ có dạng $(x, k - x)$ với $x$ là một số từ $0$ đến $k/2$ (do cặp có tính chất hoán vị nên chỉ xét từ $0$ đến $k/2$). Và với mỗi cặp, ta sẽ chọn vào kết quả là 1 trong 2 số $x$, $k-x$. Từ đó nếu gọi $cnt(x)$ là số lần xuất hiện của phần tử $x$ thì trong 2 số $x$ và $k-x$ mình sẽ chọn số có $cnt$ lớn hơn để tối ưu kết quả. Như vậy kết quả sẽ là $\sum_{x = 0}^{k/2} max(cnt(x), cnt(k-x))$ Lưu ý, công thức trên có trường hợp đặc biệt là cặp $(0, 0)$ và cặp $(k/2, k/2)$ (nếu k là số chẵn). Đối với 2 trường hợp này thì nếu $cnt$ > 0 thì chỉ chọn 1 số. ``` for i in [1, n]: a[i] = a[i] mod k cnt[a[i]] += 1 ans = 0 for i in [0, k/2]: if i = 0 or (k chẵn and i = k/2): ans += (cnt[i] > 0) else: ans += max(cnt[i], cnt[k - i]) kết quả là ans ``` #### Độ phức tạp $O(n)$ #### Code ```c #include <bits/stdc++.h> #define MAXN 100005 using namespace std; int a[MAXN], cnt[105]; int main(){ int n, k; cin >> n >> k; for(int i = 0; i < n; i++){ cin >> a[i]; a[i] = a[i] % k; cnt[a[i]]++; } int res = 0; for(int i = 0; i <= k/2; i++) if(i == 0 || i == (k+1)/2){ res += (cnt[i] > 0); }else{ res += max(cnt[i], cnt[k-i]); } cout << res << '\n'; } ``` i =