Need explaination for this code (algorithm) - c

The problem:
Larry is very bad at math - he usually uses a calculator, which worked well throughout college. Unforunately, he is now struck in a deserted island with his good buddy Ryan after a snowboarding accident. They're now trying to spend some time figuring out some good problems, and Ryan will eat Larry if he cannot answer, so his fate is up to you!
It's a very simple problem - given a number N, how many ways can K numbers less than N add up to N?
For example, for N = 20 and K = 2, there are 21 ways:
0+20
1+19
2+18
3+17
4+16
5+15
...
18+2
19+1
20+0
Input
Each line will contain a pair of numbers N and K. N and K will both be an integer from 1 to 100, inclusive. The input will terminate on 2 0's.
Output
Since Larry is only interested in the last few digits of the answer, for each pair of numbers N and K, print a single number mod 1,000,000 on a single line.
Sample Input
20 2
20 2
0 0
Sample Output
21
21
The solution code:
#include<iostream>
#include<stdlib.h>
#include<stdio.h>
using namespace std;
#define maxn 100
typedef long ss;
ss T[maxn+2][maxn+2];
void Gen() {
ss i, j;
for(i = 0; i<= maxn; i++)
T[1][i] = 1;
for(i = 2; i<= 100; i++) {
T[i][0] = 1;
for(j = 1; j <= 100; j++)
T[i][j] = (T[i][j-1] + T[i-1][j]) % 1000000;
}
}
int main() {
//freopen("in.txt", "r", stdin);
ss n, m;
Gen();
while(cin>>n>>m) {
if(!n && !m) break;
cout<<T[m][n]<<endl;
}
return 0;
}
How has this calculation been derived?
How has it come T[i][j] = (T[i][j-1] + T[i-1][j]) ?

Note: I only use n and k (lower case) to refer to some anonymous variable. I will always use N and K (upper case) to refer to N and K as defined in the question (sum and the number of portions).
Let C(n, k) be the result of n choose k, then the solution to the problem is C(N + K - 1, K - 1), with the assumption that those K numbers are non-negative (or there will be infinitely many solution even for N = 0 and K = 2).
Since the K numbers are non-negative, and the sum N is fixed, we can think of the problem as: how many ways to divide candy among K people. We can divide the candies, by lying them into a line, and put (K - 1) separator between the candies. The (K - 1) separators will divide the candies up to K portions of candies. Looking at another perspective, it is also like choosing (K - 1) positions among (N + K - 1) positions to put in the separators, then the rest of the positions are candies. So, this explains why the number of ways is N + (K - 1) choose (K - 1).
Then the problem reduce to how to find the least significant digits of C(n, k). (Since maximum of N and K is 100 as defined in maxn, we don't have to worry if the algorithm goes up to O(n3)).
The calculation uses this combinatorial identity C(n, k) = C(n - 1, k) + C(n, k - 1) (Pascal's rule). The clever thing about the implementation is that it doesn't store C(n, k) (table of result of combination, which is a jagged array), but it stores C(N, K) instead. The identity is actually present in the T[i][j] = (T[i][j-1] + T[i-1][j]):
The first dimension is actually K, the number of portions. And the second dimension is the sum N. T[K][N] will directly store the result, and according to the mathematical result derived above, is (least significant digits of) C(N + K - 1, K - 1).
Re-writing the T[i][j] = (T[i][j-1] + T[i-1][j]) back to equivalent mathematical result:
C(i + j - 1, i - 1) = C(i + j - 2, i - 1) + C(i + j - 2, i - 2), which is correct according to the identity.
The program will fill the array row by row:
The row K = 0 is already initialized to 0, using the fact that static array is initialized to 0.
It fills the row K = 1 with 1 (there is only 1 way to divide N into 1 portion).
For the rest of the rows, it sets the case N = 0 to 1 (there is only 1 way to divide 0 into K parts - all parts are 0).
Then the rest are filled with the expression T[i][j] = (T[i][j-1] + T[i-1][j]), which will refer to the previous row, and the previous element of the same row, both of which has been filled up in earlier iterations.

Let C(x, y) to be the result of x choose y, then the value of T[i][j] equals: C(i - 1 + j, j).
You can proove this by induction.
Base cases:
T[1][j] = C(1 - 1 + j, j) = C(j, j) = 1
T[i][0] = C(i - 1, 0) = 1
For the induction step, use the formula (for 0<=y<=x):
C(x,y) = C(x - 1, y - 1) + C(x - 1, y)
Therefore:
C(i - 1 + j, j) = C(i-1+j - 1, j - 1) + C(i-1+j - 1, j) = C(i-1+(j-1), (j-1)) + C((i-1)-1+j, j)
Or in other words:
T[i][j] = T[i,j-1] + T[i-1,j]
Now, as nhahtdh mentioned before, the value you are looking for is C(N + K - 1, K - 1)
which equals:
T[N+1][K-1] = C(N+1-1+K-1, K-1)
(modulo 1000000)

This is a famous problem - you can check solution here
How many ways to drop N identical balls to K boxes.
The following algorithm is a dynamic-programming solution to your problem:
Define D[i,j] to be the number of ways i numbers less than j, can sum up to j.
0 <= i < = N
1 <= j <= K
Where D[j,1] = 1 for every j.
And where j > 1 you get:
D[i,j] = D[i,j-1] + D[i-1,j-1] +...+ D[0,j-1]

The problem is known as "the integer partition problem". Basically there exists a recursive computation of the k-partition of n, but your solution is just the dynamic programming version of it (non-recursive and computing bottom-up for short).

Related

Find the frequency of number repeates (r-l+1)/2 times in range [l:r]

Given the array: A[N]. There are some queries including Li and Ri. We must Find the number that appears more than (Ri-Li+1)/2 times in range [Li:Ri].
For example:
INPUT:
N=7
1 1 3 2 3 4 3
OUTPUT:
Ranges:
[1:3] ans is :>1
[1:4] no answer
[1:7] ans is :>3
[2:7] no answer
First, I think we can use map to store the times that A[i] appears from 1 to j
And it's take up a lot of memories if N up to 5e5.
Then I sort(Increasing order) the queries so that Ri, and no more idea.
Suggestions:
Is there any efficient algorithm to this problem or any data structure to stores the frequency of A[i]: from 1 to j?
I have no idea about such data structure, but I find an solution for this problem.
If Ri - Li + 1 is odd, there may have two elements appear (Ri - Li + 1) / 2 times. Which one do you want to get? We can use the algorithm beblow to get one of them and the algorithm can get all of these two if you want.
If there are just few queries satisfy \sum (Ri - Li) are small enough, get the answer for each [Li, Ri] separately.
For each [Li, Ri],we can use a O(Ri - Li) time, O(1) auxiliary memory algorithm to get the answer. If there is a x appears exactly (Ri - Li + 1) / 2 times, at least one of three case below must happend (suppose Ri > Li).
x appears (Ri - Li + 1) / 2 times in [Li, Ri - 1].
x appears (Ri - Li + 1) / 2 times in [Li + 1, Ri].
A[Li] == A[Ri] == x.
For case 1,2 we can use 'Heavy Hitters' algorithm to find the candidate x.
So can get three candidate x for one travese, and check each of them to find the answer(see cpp code below).
int getCandidateX(int L, int R) {
int x = A[L], count = 1;
for(int i = L + 1; i <= R; ++i){
if(A[i] == x) ++count;
else if(--count == 0){
x = A[i];
count = 1;
}
}
return x;
}
int getFrequency(int L, int R, int x) {
int count = 0;
for(int i = L; i <= R; ++i) {
if(A[i] == x) ++count;
}
return count;
}
/**
* if Ri == Li, no answer
* suppose Ri > Li
* return {x, 0} and {-1,-1} if no such element
*/
pair<int,int> getAnswer(int Li, int Ri) {
int t = (Ri - Li + 1) / 2;
int x;
if((Ri - Li) & 1) {
x = getCandidateX(Li, Ri);
if(getFrequency(Li, Ri, x) == t) return {x, 0};
return {-1, -1}
}
x = getCandidateX(Li, Ri - 1);
if(getFrequency(Li, Ri, x) == t) return {x, 0};
x = getCandidateX(Li + 1, Ri);
if(getFrequency(Li, Ri, x) == t) return {x, 0};
if(A[Li] == A[Ri] && getFrequency(Li, Ri, A[Li]) == t)
return {Li, 0};
return {-1,-1}
}
When \sum (Ri - Li) is large, I found an O((m + n)logn) online solution, but it also cost a lot of memory. I conduct it as a RMQ(Range Maximum Query) problem and solve it by ST(sparse table) algorithm.
First, we can get the frequency in [L, R] of any x with O(logn) time.
We can store all the position of x in map[x] where map maps x to its position array.(we can use treemap or hashmap)
Then we can get the frequency of x in [L, R] by binary search which cost O(logn) time.
Define num[L][R] be a set of elements appear more than (R - L + 1) / 4 times in interavl [L,R]. Let val[i][k] = num[L][L + 2^k - 1], k >= 2.
Every val[i][k] has at most 4 elements, and we can calculate all val[i][k] for 0 <= i <= n and i + 2^k <= n in O(nlogn) time and O(nlogn) memory.
Because for every interval [L,R] and M1, M2 such that L <= M < R it is obvious to see that num[L][R] \subset num[L][M] \cup num[M + 1][R]. Then val[i][k] \subset val[i][k - 1] \cup val[i + 2^{k - 1} - 1][k - 1]`.
Let t as the greatest number such that 2^t <= R - L + 1 we can draw a conclusion that if x \in [L,R] appears not less than (R - L + 1) / 2 times,x must in val[L][t] or val[R - 2^t + 1][R]。
This means it is sufficient to check the frequency of every element in val[L][t] \cup val[R - 2^t - 1][t].
For every query [L,R] we can check every element in O(logn) time, so the total time is O((m + n)logn) where n is the element number of A and m is the query number.
If the question is to get the element appears exactly (Ri-Li+1)/2 + 1 times (or more), it can be solve in a more simply way.

Given two arrays and an upper limit, what is the most efficient way to get the index pair for which the sum is maximum and below the upper limit?

Given two arrays A and B and an upper limit k, what will the most efficient way to compute the index pair (i, j) such that given,
s = A[i] + B[j]
s = max(A[a] + B[b]) for a = 0, 1, 2, .. , len(A)-1 and b = 0, 1, 2, .. , len(B)-1
and
s < k
For example,
Given,
A = [9,2,5]
B = [2,1,6]
k = 5
we get,
s = 2 + 2 = 4 < 5
and hence,
i = 1 and j = 0
So the output should be (1,0)
A straight-forward approach would be looping through all the elements of A and B but that would make the worst case time complexity O(nm) where n = len(A) and m = len(B).
Is there a better way to solve this problem?
This type of problems can be solved by sorting one of the array.
One Approach could be this ::
make an array temp of tuples such that each tuple will be (value,index) where value is item of B and index is its corresponding index in B.
Now, sort this temp array with respect to first item of tuple i.e, value.
iterate through array A and using Binary Search find the Lower bound of K - A[i] in temp array. let it be at index j.
Now there are two possibilities, either A[ i ] + temp[ j ][ 0 ] > = K or < k.
If it is greater than K, than check if j - 1 exists or not and update currentMaximum if possible because this pair can be max and at the same time less than k because we found lower bound.
If it is less than K, than update currentMaximum if possible.
If you need indices than whenever you update you currentMaximum, store i and j.
In this way you can find maximum sum of pairs such that it is less than K with original index as given in array B
If order of elements does not matter than, just sort B and do same steps on B instead of temp.
Time Complexity
For sorting = O( len(B) * Log(len(B)) )
for traversing A and doing Binary Search on B = O ( len(A) * Log (len(B))) i.e, O ( nlog(n))
You can use sort for A and B. Then you can use an early break once you are >= k. The function below returns indices, s.t. A[i] + B[j] < k and A[p] + B[q] < A[i] + B[j], for all p < i and for all q < j.
def sum_less_than_k(A, B, k):
i_max = -1
j_max = -1
s_max = -np.inf
for i, a in enumerate(A):
if a + B[0] >= k:
break
for j, b in enumerate(B):
if a + b >= k:
break
if a + b > s_max:
s_max = a + b
i_max = i
j_max = j
return i_max, j_max
A.sort()
B.sort()
i, j = sum_less_than_k(A, B, k)
I wrote the code for Saurab's suggestion as well which is way faster for large k relative to what's in the list. However, for rather short lists or small k the two for loops are faster according to some sample runs.
def sum_less_than_k(A, B, k):
i_max = j_max = -1
s_max = -np.inf
for i, a in enumerate(A):
j = bisect(B, k - a - 1)
if len(B) > j > -1 and k > A[i] + B[j] > s_max:
s_max = A[i] + B[j]
i_max = i
j_max = j
return i_max, j_max
B.sort()
i, j = sum_less_than_k(A, B, k)

Find the kth lowest sum of unique pair in an array

Given an array of numbers, each number represents the difficulty of a problem. People standing in a line should choose any two problems to solve. The two chosen problems should be different and the pair of problems should not be picked by anyone previously. Since they know the difficulties they'll choose the pair whose sum of difficulties is minimum.
Find the minimum sum of difficulties for the person whose standing in kth position in the line. i.e kth minimum sum of unique pair from an array.
Approach 1: Brute force approach(O(n2)) to calculate all possible unique sum and store that in an array and sorted the unique sum array to get the kth element.
Approach 2: Sort the difficulties array and choose the minimal elements(for first 4 elements we can have 6 unique pairs. so if k is less than or equal to 6 we can use first 4 elements in the sorted array to find the minimum sum) and did the approach 1 with the minimal array.
These 2 approaches did not solve the timeout cases. Need a solution with improved time efficiency.
Note: Different problem can have same difficulty level(i.e. array can contain duplicate numbers) also and not in sorted order by default.
difficulties = [1,4,3,2,4]
Person comes first chooses: 1+2 = 3
2nd person: 1+3 = 4
3rd person: 1+4 (or) 1+4(since difficulty of two problems are 4) (or) 2+3 = 5
4th person: 2+3 (or) 1+4(based on the previous selection) = 5
Final answer needed is only the minimum sum not the actual elements.
Assume the constraints to be:
2 <= N <= 105
1 <= k <= N*(N-1)/2
1 <= difficulties[i] <= 109
where,
N is the length of the array
k is the position in which the person has to choose the problems
Assuming k <= n*(n-1)/2. If not, then no answer possible.
We can use binary search to solve the problem. We binary search on the possible sum of pairs.
Here, low = minimum sum possible i.e. low = difficulties[0] + difficulties[1], and high = maximum sum possible i.e. high = difficulties[n-1] + difficulties[n-2].
So, mid = low + (high - low)/2
Now, in 1 iteration of binary search we would count the pairs of indices (i, j), i < j such that difficulties[i] + difficulties[j] <= mid. If the count is less than k, low = mid + 1 else if count >= k, high = mid. Now, this one iteration can be done in O(NlogN).
You can do this till (high - low) > 1. So, each time you reduce your search space by half. So, total time complexity would be O(N*logN*logMaxsum) which for N <= 1e6 and difficulties[i] <= 1e18 would run in less than 1s.
Now high can be equal to low or high can be equal to low +1. The answer can be equal to low or high. Now, you just need to solve the problem whether low is a possible sum(can be solved easily in O(N) using Hashing) and no. of pairs of indices (i, j), i < j such that difficulties[i] + difficulties[j] <= low. If both conditions satify then this is your answer. If not then high is the answer.
Running an example testcase:
Lets' consider the initial array, difficulties = [1, 4, 3, 2, 4] and k = 6.
You first sort the array costing us O(NlogN). After sorting difficulties = [1, 2, 3, 4, 4]
All the pairs n*(n-1)/2 = 10 would be:
(1 + 2) => 3
(1 + 3) => 4
(1 + 4) => 5
(1 + 4) => 5
(2 + 3) => 5
(2 + 4) => 6
(2 + 4) => 6
(3 + 4) => 7
(3 + 4) => 7
(4 + 4) => 8
This is more of a pseudocode to understand the running of the logic.
sort(difficulties)
low = difficulties[0] + difficulties[1] // Minimum possible sum
high = difficulties[n-1] + difficulties[n-2] // Maximum possible sum
while(high - low > 1){
mid = low + (high - low)/2
count = all pairs (i, j) and i < j such that difficulties[i] + difficulties[j] <= mid.
if(count < k){
low = mid +1
}else{
high = mid
}
}
Iteration 1:
low = 3
high = 8
mid = 5
count = 5 [(1 + 2), (1 + 3), (1 + 4), (1 + 4), (2 + 3)]
count < k, so low = mid + 1 = 6
----------
Iteration 2:
low = 6
high = 8
mid = 7
count = 9 [(1 + 2), (1 + 3), (1 + 4), (1 + 4), (2 + 3), (2 + 4), (2 + 4), (3 + 4), (3 + 4)]
count >= k, so high= mid = 7
Now, while loop stops since high(7) - low(6) = 1.
Now, you need to check if sum 6 is possible and count of all (i, j) >= k. if it is then low is the answer and in this case it is true. So, answer = 6 for k = 6.
To implement the count thing, you can again do a binary search. Choose first index as i then you just need to find the upper bound of mid - difficulties[i] in the array [i+1, n-1]. Then increment i by 1 and repeat the same. So, you go over every index 0 <= i <= n-1 and find its upper bound in the array search space of [i+1, n-1] and this each iteration takes O(NlogN).
To see why is the last step of checking if low or high is a possible sum or not, try running the algorithm for the array difficulties = [10, 40, 30, 20, 40].
UPDATE:
Below is the complete working code with the time complexity of O(N*logN*logMaxsum) including comments for clear understanding of the logic.
#include<bits/stdc++.h>
#define ll long long int
using namespace std;
void solve();
int main(){
solve();
return 0;
}
map<int, int> m;
vector<ll> difficulties;
ll countFunction(ll sum){
/*
Function to count all the pairs of indices (i, j) such that
i < j and (difficulties[i] + difficulties[j]) <= sum
*/
ll count = 0;
int n = (int)difficulties.size();
for(int i=0;i<n-1;i++){
/*
Here the outer for loop means that if I choose difficulties[i]
as the first element of the pair, then the remaining sum is
m - difficulties[i], so we just need to find the upper_bound of this value
to find the count of all pairs with sum <= m.
upper_bound is an in-built function in C++ STL.
*/
int x= upper_bound(difficulties.begin(), difficulties.end(), sum-difficulties[i]) - (difficulties.begin() + i + 1);
if(x<=0){
/*
We break here because the condition of i < j is violated
and it will be violated for remaining values of i as well.
*/
break;
}
//cout<<"x = "<<x<<endl;
count += x;
}
return count;
}
bool isPossible(ll sum){
/*
Hashing based solution to check if atleast 1 pair with
a particular exists in the difficultiesay.
*/
int n = (int) difficulties.size();
for(int i=0;i<n;i++){
/*
Choosing the ith element as first element of pair
and checking if there exists an element with value = sum - difficulties[i]
*/
if(difficulties[i] == (sum - difficulties[i])){
// If the elements are equal then the frequency must be > 1
if(m[difficulties[i]] > 1){
return true;
}
}else{
if(m[sum - difficulties[i]] > 0){
return true;
}
}
}
return false;
}
void solve(){
ll i, j, n, k;
cin>>n>>k;
difficulties.resize(n);
m.clear(); // to run multiple test-cases
for(i=0;i<n;i++){
cin>>difficulties[i];
m[difficulties[i]]++;
}
sort(difficulties.begin(), difficulties.end());
// Using binary search on the possible values of sum.
ll low = difficulties[0] + difficulties[1]; // Lowest possible sum after sorting
ll high = difficulties[n-1] + difficulties[n-2]; // Highest possible sum after sorting
while((high-low)>1){
ll mid = low + (high - low)/2;
ll count = countFunction(mid);
//cout<<"Low = "<<low<<" high = "<<high<<" mid = "<<mid<<" count = "<<count<<endl;
if (k > count){
low = mid + 1;
}else{
high = mid;
}
}
/*
Now the answer can be low or high and we need to check
if low or high is a possible sum and does it satisfy the constraints of k.
For low to be the answer, we need to count the number of pairs with sum <=low.
If this count is >=k, then low is the answer.
But we also need to check whether low is a feasible sum.
*/
if(isPossible(low) && countFunction(low)>=k){
cout<<low<<endl;
}else{
cout<<high<<endl;
}
}

Maximizing count of distinct numbers that produce a given sum 'k'

I need help with this dynamic programming problem.
Given a positive integer k, find the maximum number of distinct positive integers that sum to k. For example, 6 = 1 + 2 + 3 so the answer would be 3, as opposed to 5 + 1 or 4 + 2 which would be 2.
The first thing I think of is that I have to find a subproblem. So to find the max sum for k, we need to find the max sum for the values less than k. So we have to iterate through the values 1 -> k and find the max sum for those values.
What confuses me is how to make a formula. We can define M(j) as the maximum number of distinct values that sum to j, but how do I actually write the formula for it?
Is my logic for what I have so far correct, and can someone explain how to work through this step by step?
No dynamic programming is need. Let's start with an example:
50 = 50
50 = 1 + 49
50 = 1 + 2 + 47 (three numbers)
50 = 1 + 2 + 3 + 44 (four numbers)
50 = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 14 (nine numbers)
Nine numbers is as far as we can go. If we use ten numbers, the sum would be at least 1 + 2 + 3 + ... + 10 = 55, which is greater than 50 - thus it is impossible.
Indeed, if we use exactly n distinct positive integers, then the lowest number with such a sum is 1+2+...+n = n(n+1)/2. By solving the quadratic, we have that M(k) is approximately sqrt(2k).
Thus the algorithm is to take the number k, subtract 1, 2, 3, etc. until we can't anymore, then decrement by 1. Algorithm in C:
int M(int k) {
int i;
for (i = 1; ; i++) {
if (k < i) return i - 1;
else k -= i;
}
}
The other answers correctly deduce that the problem essentially is this summation:
However this can actually be simplified to
In code this looks like : floor(sqrt(2.0 * k + 1.0/4) - 1.0/2)
The disadvantage of this answer is that it requires you to deal with floating point numbers.
Brian M. Scott (https://math.stackexchange.com/users/12042/brian-m-scott), Given a positive integer, find the maximum distinct positive integers that can form its sum, URL (version: 2012-03-22): https://math.stackexchange.com/q/123128
The smallest number that can be represented as the sum of i distinct positive integers is 1 + 2 + 3 + ... + i = i(i+1)/2, otherwise known as the i'th triangular number, T[i].
Let i be such that T[i] is the largest triangular number less than or equal to your k.
Then we can represent k as the sum of i different positive integers:
1 + 2 + 3 + ... + (i-1) + (i + k - T[i])
Note that the last term is greater than or equal to i (and therefore different from the other integers), since k >= T[i].
Also, it's not possible to represent k as the sum of i+1 different positive integers, since the smallest number that's the sum of i+1 different positive integers is T[i+1] > k because of how we chose i.
So your question is equivalent to finding the largest i such that T[i] <= k.
That's solved by this:
i = floor((-1 + sqrt(1 + 8k)) / 2)
[derivation here: https://math.stackexchange.com/questions/1417579/largest-triangular-number-less-than-a-given-natural-number ]
You could also write a simple program to iterate through triangular numbers until you find the first larger than k:
def uniq_sum_count(k):
i = 1
while i * (i+1) <= k * 2:
i += 1
return i - 1
for k in xrange(20):
print k, uniq_sum_count(k)
I think you just check if 1 + ... + n > k. If so, print n-1.
Because if you find the smallest n as 1 + ... + n > k, then 1 + ... + (n-1) <= k. so add the extra value, say E, to (n-1), then 1 + ... + (n-1+E) = k.
Hence n-1 is the maximum.
Note that : 1 + ... + n = n(n+1) / 2
#include <stdio.h>
int main()
{
int k, n;
printf(">> ");
scanf("%d", &k);
for (n = 1; ; n++)
if (n * (n + 1) / 2 > k)
break;
printf("the maximum: %d\n", n-1);
}
Or you can make M(j).
int M(int j)
{
int n;
for (n = 1; ; n++)
if (n * (n + 1) / 2 > j)
return n-1; // return the maximum.
}
Well the problem might be solved without dynamic programming however i tried to look at it in dynamic programming way.
Tip: when you wanna solve a dynamic programming problem you should see when situation is "repetitive". Here, since from the viewpoint of the number k it does not matter if, for example, I subtract 1 first and then 3 or first 3 and then 1; I say that "let's subtract from it in ascending order".
Now, what is repeated? Ok, the idea is that I want to start with number k and subtract it from distinct elements until I get to zero. So, if I reach to a situation where the remaining number and the last distinct number that I have used are the same the situation is "repeated":
#include <stdio.h>
bool marked[][];
int memo[][];
int rec(int rem, int last_distinct){
if(marked[rem][last_distinct] == true) return memo[rem][last_distinct]; //don't compute it again
if(rem == 0) return 0; //success
if(rem > 0 && last > rem - 1) return -100000000000; //failure (minus infinity)
int ans = 0;
for(i = last_distinct + 1; i <= rem; i++){
int res = 1 + rec(rem - i, i); // I've just used one more distinct number
if(res > ans) ans = res;
}
marked[rem][last_distinct] = true;
memo[rem][last_distinct] = res;
return res;
}
int main(){
cout << rec(k, 0) << endl;
return 0;
}
The time complexity is O(k^3)
Though it isn't entirely clear what constraints there may be on how you arrive at your largest discrete series of numbers, but if you are able, passing a simple array to hold the discrete numbers, and keeping a running sum in your functions can simplify the process. For example, passing the array a long with your current j to the function and returning the number of elements that make up the sum within the array can be done with something like this:
int largest_discrete_sum (int *a, int j)
{
int n, sum = 0;
for (n = 1;; n++) {
a[n-1] = n, sum += n;
if (n * (n + 1) / 2 > j)
break;
}
a[sum - j - 1] = 0; /* zero the index holding excess */
return n;
}
Putting it together in a short test program would look like:
#include <stdio.h>
int largest_discrete_sum(int *a, int j);
int main (void) {
int i, idx = 0, v = 50;
int a[v];
idx = largest_discrete_sum (a, v);
printf ("\n largest_discrete_sum '%d'\n\n", v);
for (i = 0; i < idx; i++)
if (a[i])
printf (!i ? " %2d" : " +%2d", a[i]);
printf (" = %d\n\n", v);
return 0;
}
int largest_discrete_sum (int *a, int j)
{
int n, sum = 0;
for (n = 1;; n++) {
a[n-1] = n, sum += n;
if (n * (n + 1) / 2 > j)
break;
}
a[sum - j - 1] = 0; /* zero the index holding excess */
return n;
}
Example Use/Output
$ ./bin/largest_discrete_sum
largest_discrete_sum '50'
1 + 2 + 3 + 4 + 6 + 7 + 8 + 9 +10 = 50
I apologize if I missed a constraint on the discrete values selection somewhere, but approaching in this manner you are guaranteed to obtain the largest number of discrete values that will equal your sum. Let me know if you have any questions.

sum's sum of divizors of numbers less than or equal to N

I really need some help at this problem:
Given a positive integer N, we define xsum(N) as sum's sum of all positive integer divisors' numbers less or equal to N.
For example: xsum(6) = 1 + (1 + 2) + (1 + 3) + (1 + 2 + 4) + (1 + 5) + (1 + 2 + 3 + 6) = 33.
(xsum - sum of divizors of 1 + sum of divizors of 2 + ... + sum of div of 6)
Given a positive integer K, you are asked to find the lowest N that satisfies the condition: xsum(N) >= K
K is a nonzero natural number that has at most 14 digits
time limit : 0.2 sec
Obviously, the brute force will fall for most cases with Time Limit Exceeded. I haven't find something better than it yet, so that's the code:
fscanf(fi,"%lld",&k);
i=2;
sum=1;
while(sum<k) {
sum=sum+i+1;
d=2;
while(d*d<=i) {
if(i%d==0 && d*d!=i)
sum=sum+d+i/d;
else
if(d*d==i)
sum+=d;
d++;
}
i++;
}
Any better ideas?
For each number n in range [1 , N] the following applies: n is divisor of exactly roundDown(N / n) numbers in range [1 , N]. Thus for each n we add a total of n * roundDown(N / n) to the result.
int xsum(int N){
int result = 0;
for(int i = 1 ; i <= N ; i++)
result += (N / i) * i;//due to the int-division the two i don't cancel out
return result;
}
The idea behind this algorithm can aswell be used to solve the main-problem (smallest N such that xsum(N) >= K) in faster time than brute-force search.
The complete search can be further optimized using some rules we can derive from the above code: K = minN * minN (minN would be the correct result if K = 2 * 3 * ...). Using this information we have a lower-bound for starting the search.
Next step would be to search for the upper bound. Since the growth of xsum(N) is (approximately) quadratic we can use this to approximate N. This optimized guessing allows to find the searched value pretty fast.
int N(int K){
//start with the minimum-bound of N
int upperN = (int) sqrt(K);
int lowerN = upperN;
int tmpSum;
//search until xsum(upperN) reaches K
while((tmpSum = xsum(upperN)) < K){
int r = K - tmpSum;
lowerN = upperN;
upperN += (int) sqrt(r / 3) + 1;
}
//Now the we have an upper and a lower bound for searching N
//the rest of the search can be done using binary-search (i won't
//implement it here)
int N;//search for the value
return N;
}

Resources