DIVSUBS - Editorial

Problem link : contest practice

Difficulty : Simple

Pre-requisites : Pigeonhole principle

Problem : Find a nonempty subset of the given multiset with the sum of elements divisible by the size of the original multiset or state that the required subset doesn’t exist.

Explanation :

Claim:

There is always such a subset. Moreover, there is always a consecutive subsegment of any sequence of numbers that corresponds to the multiset’s elements with the sum divisible by the multiset’s size.

Proof:

Let’s denote a1 + a2 + … + ak by bk. So, we obtain:

  • b0 = 0
  • b1 = a1
  • b2 = a1 + a2
  • bN = a1 + a2 + … + aN

It is easy to see that aL + aL+1 + … + aR (L <= R) equals to bR - bL-1. Therefore, if there are two values with equal residues modulo N among b0, b1, …, bN then we take the first one for L-1 and the second one for R and the required subsegment is found.

There are N+1 values of bi and N possible residues for N. So, according to the pigeonhole principle the required subsegment will always exist.

Some implementation details:

While calculating the value of bi you should use that bi equals to bi-1 + ai, that allows you to precompute all bs in O(N) time. Practically, only bi modulo N are important. Then you can just sort the numbers along with their indices in order to find the duplicates among the residues.

Solutions : Setter Tester

11 Likes

I used very very very slow recursive solution:

from __future__ import division
def read_mapped(func=lambda x:x):
    return map(func, raw_input().strip().split(" "))
def read_int():
    return int(raw_input().strip())
def read_str():
    return raw_input().strip()
def read_float():
    return float(raw_input().strip())

T = read_int()

def solve(a, n, s):
    acc = 0
    for elem in s:
        acc += original_a[elem]

    if acc%n==0 and acc!=0:
        return s

    if a==[]:
        return False

    return solve(a[:-1], n, s) or solve(a[:-1], n, s+[len(a)-1])


for case in xrange(T):
    n = read_int()
    a = read_mapped(int)
    global original_a
    original_a = a

    res = solve(a, n, [])
    if res is False:
        print "-1"
    else:
        print len(res)
        print " ".join(map(lambda a: str(a+1), res))

Any way to speed this up?

but what about “any number can be taken in the subset no more than once.”?
it is slightly misleading i thought that repetition of number is not allowed ,say, 2 can be used only once.

2 Likes

this was supposed to be a subset and the above solution seems to be for subsequence of the set??
subsequence is {a[i],a[i+1], … , a[j]} for 1<=i<=j<=n and subset is {a[i1], a[i2], a[i3], … , a[ik]} for 1<=k<=n…

I think this will work for all test cases

My solution is using Dynamic programming

http://code.hackerearth.com/818994d

code in above link

i also thought same.
Eg : for case
2
3
2 2 2
3
2 5 8

my program gave
-1
3
1 2 3

can anyone solve this

You are given a string S and you have to count how many subsequence of this string does not have same character at adjacent positions. Subsequence of string S can be obtained from deleting zero or more characters from string S.

Example: let, S = “aba” then possible subsequences are “a”, “ab”, “aba”, “aa”, “b”, “ba”, “a” and “”(empty string). But among the subsequences all are valid except “aa”.

Input
First line of the input contains 1 ≤ T ≤ 100 number of test cases. Each of the following T lines contains a string which have positive and contains at most 1000 lowercase English letters.

Output
Output a single line containing case number and the number of subsequence. As the result can be large print it by modulo 100009.

@xcwgf666
i think your explanation is seriously flawed, as the elements can be taken once only.
for eg., 2 2 2: here, {2} is not divisible by 3.

Can someone please check my solution
I tried to implement the editorial but am getting WA.

http://www.codechef.com/viewsolution/3944205

There is always such a subset. Moreover, there is always a consecutive subsegment (SUBSEQUENCE) of any sequence of numbers that corresponds to the multiset’s elements with the sum divisible by the multiset’s size

index values can be taken only once.The same element can appear more than once.Therefore the answer is {2,2,2}

@kanansa, maybe I misunderstood the problem statement, as it was written: “If the required subset exists, output two lines. Output the size of the subset on the first line and output the list of indices of the multiset’s element that form the required subset. Of course, any number can be taken in the subset no more than once.”

A few more insights:

  1. While implementing the technique presented in the editorial, sorting is not required to find duplicates(though it will easily pass). First we create an array positions[] and fill it with -1’s. Then we loop through the array in which we stored our multi-set, calculating the corresponding b values at each step. When we’re at position i in the loop, let bi%n=j. Now if positions[j] is equal to -1, we set positions[j] = i. If it’s not equal to -1, then we’ve found our duplicate. That let’s us solve the problem in O(n) time.

  2. If the problem were instead this: Given a multi-set of size n, find a subset of this which is divisible by a number m such that 0<m<n. The pigeon-hole principle still holds, and we could solve using the same method. (In fact we can say that there must exist atleast n+1-m distinct such subsets)
    Amazing isn’t it?

Could someone discuss an efficient method to solve the problem if m>n. (when the pigeon-hole principle wont hold). More efficient than the obvious O(n^2) dynamic programming solution?

Learned a lot from this problem! It was very insightful :slight_smile: Thanks!

3 Likes

I have difficulty in understanding the claim and its proof. Please can someone give a intuitive reasoning with an example ? An example will make things more clear. Thank you!

1 Like

please any one can check why my solution is giving runtime error-It run fine http://www.codechef.com/viewsolution/3945501

@krish you have used n in your code before its initialisation so correct it first

1 Like

I corrected this And accepted…thanks @ma5termind

@all i was not able to recognise the use of pegion hole principle when i first saw this problem and so i thought differently and came up with a new idea (new to me not neccesarily for all) which is not very efficient but can be used to get 61 points and can be optimised to get 100 points.
here is my approach
firstly i thought any sum consists of either (one element + some existing sum ) or one element. so i maintained two arrays one for the sum and other for index of the new element.if it consists of only one element then i marked sum as -1 for that value . now i need to mark the sum only once and as soon as i get zero mark field marked it means it is possible to form such a subset from the existing elements. here is the implementation of my approach.
it is quite easy to think and can be solved other problems too so have a look you will learn something new.

#include<bits/stdc++.h>
#include
using namespace std;
vector< vector > mat;
#define all(b) b.begin(),b.end()
vector arr,S,sum,idx;
int main(){

int t;

cin>>t;

while(t–){

int n;

cin>>n;

arr.resize(n);

S.resize(n);

idx.resize(n);

sum.resize(n);

fill(all(S),0);

for(int i=0;i<n;i++){

  cin>>arr[i];

  arr[i]%=n;

}

int temp[n];

for(int i=0;i<n;i++){

for(int k=0;k<n;k++) temp[k]=S[k];

for(int j=n-1;j>=0;j--)

{

    if(S[j]&&!temp[(j+arr[i])%n])

    { temp[(j+arr[i])%n]=true;

      sum[(j+arr[i])%n]=j;

      idx[(j+arr[i])%n]=i;

    }

}

for(int k=0;k<n;k++)

  S[k]=temp[k];



if(S[arr[i]%n]==false){

   S[arr[i]%n]=true;

   sum[(arr[i])%n]=-1;

   idx[(arr[i])%n]=i;

}

if(S[0]) break;

}

int count=0,id;

arr.clear();

if(S[0]){

id=0;

do{count++;id=sum[id];}while(id!=-1);

cout<<count<<endl;

id=0;

do{cout<<idx[id]+1<<endl;id=sum[id];}while(id!=-1);

}else{

cout<<-1<<endl;

}

}
return 0;
}

i want you have a loook over the approach that i have posted just now you will love it and it is quite intutive too. because everyone does nt know about pegion hole principle.:smiley:

hey i’m getting runtime error (SIGXFSZ). plz anyone tell me the fault…
http://www.codechef.com/viewsolution/3946969