Subset Sums

Find the last 3 3 digits of the number of subsets (summing to 1000 1000 ) of the set of positive integers from 1 1 to 100 100 (both inclusive).

For example, the set:

{ 1 , 16 , 30 , 43 , 47 , 52 , 53 , 55 , 57 , 60 , 64 , 67 , 68 , 69 , 71 , 72 , 75 , 100 } \lbrace 1, 16, 30, 43, 47, 52, 53, 55, 57, 60, 64, 67, 68, 69, 71, 72, 75, 100 \rbrace

sums to 1000 1000 and it is a subset of the set of positive integers from 1 1 to 100 100 (inclusive), so it would be included.

Subsets do not have ordered elements and a subset can not contain repeats of elements.


The answer is 413.

This section requires Javascript.
You are seeing this because something didn't load right. We suggest you, (a) try refreshing the page, (b) enabling javascript if it is disabled on your browser and, finally, (c) loading the non-javascript version of this page . We're sorry about the hassle.

3 solutions

Joe Ill
Jan 1, 2014

I had gotten 5983373858461353469 5983373858461353469 from using an array int64 variables instead of BigInteger variables to store intermediate solutions. I had also requested that this problem be tagged under #ComputerScience instead.

Since checking through all 2 100 2^{100} subsets would take an impossibly long time (even for a standard computer), a faster approach is needed. The one which I came up with is inspired by generating functions. More specifically, the number of subsets which sum to 1000 1000 is given by the coefficient of x 1000 x^{1000} in the product i = 1 100 ( 1 + x i ) \prod\limits_{i = 1}^{100} (1 + x^{i}) . I will not explain this here, but this is the basis for the solution shown here.

For every element k k in the set of integers from 1 1 to 100 100 inclusive, k k is either included in a subset, or it is not. Therefore, if there is already a running list of the number of subsets which sum to a particular value, it is possible to add on the subsets which include k k to the running list. For example:

Starting:

Subsets with sum 0 0 : 1 1

k = 1 k = 1 :

Subsets with sum 0 0 : 1 1

Subsets with sum 1 1 : 0 + 1 = 1 0 + 1 = 1

k = 2 k = 2 :

Subsets with sum 0 0 : 1 1

Subsets with sum 1 1 : 1 1

Subsets with sum 2 2 : 0 + 1 = 1 0 + 1 = 1

Subsets with sum 3 3 : 0 + 1 = 1 0 + 1 = 1

k = 3 k = 3 :

Subsets with sum 0 0 : 1 1

Subsets with sum 1 1 : 1 1

Subsets with sum 2 2 : 1 1

Subsets with sum 3 3 : 1 + 1 = 2 1 + 1 = 2

Subsets with sum 4 4 : 0 + 1 = 1 0 + 1 = 1

Subsets with sum 5 5 : 0 + 1 = 1 0 + 1 = 1

Subsets with sum 6 6 : 0 + 1 = 1 0 + 1 = 1

k = 4 k = 4 :

Subsets with sum 0 0 : 1 1

Subsets with sum 1 1 : 1 1

Subsets with sum 2 2 : 1 1

Subsets with sum 3 3 : 2 2

Subsets with sum 4 4 : 1 + 1 = 2 1 + 1 = 2

Subsets with sum 5 5 : 1 + 1 = 2 1 + 1 = 2

Subsets with sum 6 6 : 1 + 1 = 2 1 + 1 = 2

Subsets with sum 7 7 : 0 + 2 = 2 0 + 2 = 2

Subsets with sum 8 8 : 0 + 1 = 1 0 + 1 = 1

Subsets with sum 9 9 : 0 + 1 = 1 0 + 1 = 1

Subsets with sum 10 10 : 0 + 1 = 1 0 + 1 = 1

Continuing the pattern up to 100 100 gives that the number of subsets is 633172672364586108413 633172672364586108413 . Another possible optimization is only storing the values mod 1000 1000 , since not only the answer will be in a more convenient form, but if using a language like C++ or Java, 16 or 32 bit integers will suffice instead of the otherwise required BigIntegers.

Here is a snippet of code from my Java solution:

N = 100;

K = 1000;

arr = new BigInteger[K + 1];

Arrays.fill(arr, BigInteger.ZERO);

arr[0] = BigInteger.ONE;

for(int i = 1; i < N + 1; i++) {

    for(int j = K - i; j > -1; j--) {

        arr[j + i] = arr[j + i].add(arr[j]);

    }

}

System.out.println(arr[1000].toString());

Let m m be a positive integer. Define f ( n , m ) f(n,m) to be the number of subsets of { 1 , 2 , , n } \{1,2,\ldots,n\} such that the sum of elements in the subset is m m . Then I got the following recursive relation:

f ( n , 1 ) = 1 f(n,1) =1 .

f ( 1 , m ) = 0 f(1,m)=0 if m > 1 m>1 .

For m > 1 m>1 and n > 1 n>1 :

f ( n , m ) = f ( n 1 , m ) + f ( n 1 , m n ) f(n,m) = f(n-1, m) + f(n-1, m-n) if m > n m>n ,

f ( n , m ) = f ( n 1 , m ) + 1 f(n,m) = f(n-1, m) + 1 if m = n m=n ,

f ( n , m ) = f ( n 1 , m ) f(n,m) = f(n-1, m) if m < n m<n .

I wrote a C program (I don't know how to post the codes like you did above and I haven't programmed for long time), but it didn't end up with the answer you got (my answer is 413). I am not sure where it went wrong. [EDIT] OK, looks no need to do anything for the body of the main function. Somehow, it doesn't format correctly if includes everything.

long i, j;
long a[101][1001];

a[1][1] = 1;

for (i=2; i<=100; i++) {
    a[i][1] = 1;
}

for (j=2; j<=1000; j++) {
    a[1][j] = 0;
}

for (j=2; j<=1000; j++) {
    for (i=2; i<=100; i++) {
        if (j > i) 
            a[i][j] = (a[i-1][j] + a[i-1][j-i]) % 1000;
        else if (j == i) 
            a[i][j] = a[i-1][j] + 1;
        else
            a[i][j] = a[i-1][j];
    }
    printf ("%d\t%d\t%d\n", i-1,j, a[i-1][j]);
}

George G - 7 years, 5 months ago

633172672364586108413-5983373858461353469 = 2^64*34, so you indeed experienced overflow.

Crefin Baras - 7 years, 5 months ago

Log in to reply

So you are saying 413 is the correct answer instead of 469? Time to dispute.

George G - 7 years, 5 months ago

Log in to reply

I got 413 as well through both a C++ program and an Excel program.

Crefin Baras - 7 years, 5 months ago

Log in to reply

@Crefin Baras It is definitely 413. I used Mathematica 9 to double check. Wasted 3 hours on this...........

Anh Tuong Nguyen - 7 years, 5 months ago

633172672364586108413, I am using maple...

pebrudal zanu - 7 years, 5 months ago

The answer should be 413

Phúc Hoàng Vũ - 7 years, 5 months ago

I agree. This should be tagged with #ComputerScience

Brian Riccardi
Sep 30, 2014

I wrote a simple C++ program to recursively compute the number of subsets knowing the last integer taken and the sum of all integers in the subset I'm matching.

To speed up the algorithm we can see that there are some sub-problems that we have to compute more than once: it's time to DP! We just have to save our results into a matrix and return them when necessary.

Time complexity O( N^3 ) where N is the number of starting elements.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <string.h>
using namespace std;

int mem[105][100*101/2 +1];

int subset(int last, int sum)
{
        if( mem[last][sum]!=-1 ) return mem[last][sum];
        if(sum>1000) return mem[last][sum]=0;
        if(sum==1000) return mem[last][sum]=1;
        int numb=0;
        for(int i=last+1; i<=100; i++) numb+=subset(i,sum+i);

        return mem[last][sum]=numb%1000;
}

int main()
{
        int numb=0;
        memset( mem, -1, sizeof(mem) );

        for(int i=1; i<=100; i++) numb+=subset(i,i);

        cout << numb%1000 << endl;

    return 0;
}

Have a look at this

Replace the first two lines with:

Numbers=xrange(1,101)
Maximum=1000

And run the code!

There is a complete explanation in Stackoverflow

0 pending reports

×

Problem Loading...

Note Loading...

Set Loading...