Divisible subsets
Problem statement
Given a multiset with n integers, find such a non-empty subset of it that the sum of the subset’s elements is divisible by N.
If many valid subsets are there, then print any.
Pre-requisites:
- The pigeonhole principle
- Subarrays
Problem explanation
Let’s look at the following example.
-
N=4 -
array= [4, 6, 10, 3]
Condition = the sum of the subset must be divisible by N (that is 4 in this example )
Some of the valid subsets are:
-
{4}
-
{6, 10}
Solution
We’ll prove that there will always exist a subarray of the array whose sum is divisible by N.
Let’s proceed with an example.
-
N= 5 -
array= [1, 2, 3, 5, 7]
We’ll first create a cumulative sum array, cumArray = [1, 3, 6, 11, 18]
Here,
cumArray [i] represents the sum of subarray (0, i). We’ll change this cumArray to cumArray%N.
cumArray = [1, 3, 1, 1, 3]
Now, if any cumArray[ i ] == 0, this will mean that:
-
The sum of subarray (0, i)%
N==0 -
Thus subarray found.
Else:
-
cumArrayhasNvalues. -
Since we changed
cumArraytocumArray%N, this means values in cumArray can only be in the range [0, N-1]. Which means there could be at max N different values incumArray. But since we already checked there exists no 0 incumArray, thuscumArraycan now only haveN-1 different value. -
Now, According to the pigeonhole principle, at least 1 value in
cumArraywill occur twice. -
This means there always will exist at least one (a,b) pair such that:
-
cumArray[ a]%N=cumArray[ b]%N -
Therefore, the sum of subarray (a, b) is divisible by
N. -
Thus the subarray is found.
-
Hence, we proved that in either case, a subarray will exist with sum divisible by N.
Now, as we know it, we now do not need it to generate the whole cumArray first and then find the required subarray. We could simply find the required subarray whilst calculating the cumArray.
If x is the sum until ith index, then we just need to check if either x=0 or x occurred in cumArray previously. If yes, then we got the required subarray otherwise add x to cumArray and check for i+1th index.
Solution
Input
-
The first line of the input contains an integer
Tdenoting the number of test cases. -
The first line of each test consists of a single integer
Nwhich is the size of the multiset. -
The second line of each test contains
Nspace-separated integers which is the multiset’s elements.
Note. Press
enter/return key(↵) after each line, in order to input the next line.
Output
-
Print -1 if the required subset doesn’t exist.
-
Otherwise print two lines, first the size of the subset, then the space-separated indices of the subset.
Example
Input
- 1
- 5
- 2 4 2 9 3
Output
- 3
- 2 3 4
t = int(input())# t - test casesfor _ in range(t):N = int(input())# N - size of arrayarray = list(map(int,input().split()))# array - array of N numbers.sumx = 0sumxIndex = {}for i in range(0,N):sumx = (sumx + array[i])%Nif (sumx==0) :# sum of subarray [0,i] is divisible by N.left = 0right = ibreakif (sumx in sumxIndex.keys()):# sum of subarray [prev index of sumx in sumIndex, i] is divisible by Nleft = sumxIndex[sumx]+1right = ibreaksumxIndex[sumx] = iprint(right-left+1)for index in range(left,right+1):print(index+1,end=" ")print()
Enter the input below
Code explanation
-
Line 1: Take the number of test cases(
t) as input. -
Line 3: Start a
forloop for each test case. -
Line 5: Take the number of elements(
N) as input. -
Line 7: Store N space-separated integers in a list (
array) as input. -
Line 10:
sumxwill store the sum until the current index. -
Line 11:
sumxIndexwill store thesumxwith respective indices. -
Example:
-
N= 5 -
Array = [1,3,4,10,5]
- At index 0 ->
sumx=1%5=1 ->sumxIndex= { 1:0 } - At index 1 ->
sumx=3%5=3 ->sumxIndex= { 1:0 , 3:4 } - At index 2 ->
sumx=7%5=2 ->sumxIndex= { 1:0 , 3:4 , 2:2 }
- At index 0 ->
-
-
Line 13: Start
forloop from [0-N]. -
Line 14: Since the sum until the
ith element = the sum untili-1th element +array[i]. Thus,sumx= (sumx+array[i] )%N. -
Line 16: Check if
sumx=0.- Line 15: If yes, then subarray [0,
i] will be the required subarray. Thus, putting left = 0, right = i and breaking the loop.
- Line 15: If yes, then subarray [0,
-
Line 22: Check if
sumxalready occurred previously insumxIndex.- Line 24: If yes, then
left= previous index at whichsumxoccured insumxIndex+ 1. ,right=iand breaks the loop.
- Line 24: If yes, then
-
Line 31: Print the size of found subarray i.e.
right-left+1. -
Line 33: Now, for printing the indices of the subarray starting
forloop forifrom range = [left,right].