Can we solve this using dynamic programming? - algorithm

Find the number of subsequences of size n, with sum such that after taking modulo m, the sum became greater or equal to x.
Where:
1 <= n <= 42
1 <= m <= 10^9
0 <= x < m
How to solve this?

This problem is easier to solve with a search technique called "Meet in the middle". As Peter de Rivaz suggests you can split up your input into two sets A and B, each with 21 or less elements.
Step 1:
There are 2^|A| combinations of elements in A, and for each of these calculate the sum mod m and store this in a table T. Sort the table T.
Step 2:
For each combination c of the 2^|B| combinations of elements of B, calculate the sum s of c mod m. Now you can determine the range i->j s.t. s + i >= x mod m, using binary search on T you can determine the number of table entries of T that are in the required range.
The running time of this is O(2^{n/2} * n) which for n = 42 is computable.

Related

Idea of dynamic programming solution

Given natural number N (1 <= N <= 2000), count the number of sets of natural numbers with the sum equal to N, if we know that ratio of any two elements in given set is more than 2
(for any x, y in given set: max(x, y) / min(x, y) >= 2)
I am trying to use given ratio so it would be possible to count the sum using geometry progression formula, but I haven't succeeded yet. Somehow it's necessary to come up with dynamic programming solution, but I have no idea how to come up with a formula
As Stef suggested in the comments, if you count the number of ways you can make n, using numbers that are at most k, you can calculate this using dynamic programming. For a given n, k, either you use k or you don't: if you do, then you have n-k left, and can use numbers <= k/2, and if you don't, then you still have n, and can use numbers <= k-1. It's very similar to a coin change algorithm, or to a standard algorithm for counting partitions.
With that, here's a program that prints out the values up to n=2000 in the sequence:
N = 2000
A = [[0] * (i+1) for i in range(N+1)]
A[0][0] = 1
for n in range(1, N+1):
for k in range((n+1)//2, n+1):
A[n][k] = A[n-k][min(n-k, k//2)] + A[n][k-1]
for i in range(N+1):
print(i, A[i][i])
It has a couple of optimizations: A[n, k] is the same as A[n, n] for k>n, and A[n, k]=0 when 2k+1 < N (because if you use k, then the largest integer you can get is at most k+k/2+k/4+... <= 2k-1 -- the infinite sum is 2k, but with integer arithmetic you can never achieve this). These two optimizations give a speedup factor of 2 each, compared to computing the whole (n+1)x(n+1) table.
With these two optimizations, and the array-based bottom-up dynamic programming approach, this prints out all the solutions in around 0.5s on my machine.

Count "cool" divisors of given number N

I'm trying to solve pretty complex problem with divisors and number theory.
Namely for a given number m we can say that k is cool divisor if k<m k|m (k divides m evenly), and for a given number n the number k^n (k to the power of n) is not divisor of m. Let s(x) - number of cool divisors of x.
Now for given a and b we should find D = s(a) + s(a+1) + s(a+2) + s(a+3) + ... + s(a+b).
Limits for all values:
(1 <= a <= 10^6), (1 <= b <= 10^7), (2<=n<=10)
Example
Let's say a=32, b=1, n=3;
x = 32, n = 3 divisors of 32 are {1,2,4,8,16,32}. However only {4,8,16} fill the conditions so s(32) = 3
x = 33, n = 3 divisors of 33 are {1,3,11,33}. Only the numbers {3,11} fill the conditions so s(33)=2;
D = s(32) + s(33) = 3 + 2 = 5
What I have tried
We should answer all those questions for 100 test cases in 3 seconds time limit.
I have two ideas, the first one: I iterate in the interval [a, a+b] and for each value i in the range I check how many cool divisors are there for that value, we can check this in O(sqrt(N)) if the function for getting number of power of N is considered as O(1) so the total function for this is O(B*sqrt(B)).
The second one, I'm now sure if it will work and how fast it will be. First I do a precomputation, I have a for loop that iterates from 1 to N, where N = 10^7
and now in the range [2, N] for each number whose divisor is i, where i is in the range [2,N] and I check if i to the power of n is not divisor of j then we update that the number j has one more cool divisor. With this I think that the complexity will be O(NlogN) and for the answers O(B).
Your first idea works but you can improve it.
Instead of checking all numbers from 1 to sqrt(N) whether they are cool divisors, you can factorize N=*p0^q0*p1^q1*p2^q2...pk^qk*. Then the number of cool divisors should then be (q0+1)(q1+1)...(qk+1) - (q0/n+1)(q1/n+1)...(qk/n+1).
So you can first preprocess and find out all the prime numbers using some existing algo like Sieve of Eratosthenes and for each number N between [a,a+b] you do a factorization. The complexity should be roughly O(BlogB).
Your second idea works as well.
For each number i between [2,a+b], you can just check the multiples of i between [a,a+b] and see whether i is a cool divisor of those multiples. The complexity should be O(BlogB) as well. Some tricks can be played in this idea to speed up the program is that, once you don't need to use divide/mod operations from time to time to check whether i is a cool divisor. You can compute the first number m between [a, a+b] that i^n|m. This m should be m=ceiling(a/(i^n))(i^n). And then you know i^n|m+p*i does not hold for p between [1,i^(n-1) - 1] and holds for p=i^n-1. Basically, you know i is not a cool divisor every i^(n-1) multiples, and you do not need to use divide/mod to figure it out, which will speed the program up.

Approximate with sum of Fractions

Suppose the result of adding fractions a/b and c/d is (a + c)/(b + d). Similarly the result of adding 3 fractions a/b, c/d, e/f is (a + c + e)/(b + d + f), and so on.
I have the following problem I could not solve.
Given an array A with n fractions a1/b1, a2/b2, ...., an/bn, a number k< n, and a fraction c/d.
I need to test if it is possible to take exactly k indexes {i1,i2,...,ik} such a way the sum of A[i1]+A[i2]+...+A[ik] >= c/d.
If this is possible print the indexes.
For example:
If you have the fractions 1/4, 300/600, 400/400, k=2 and c/d = 400/400
Then the answer is NO.
On the other hand, if c/d =400/404 then the answer is 1 and 3 because 1/4+400/400 = 401/404 >= 400/404.
Thanks!
Notice that if 0 <= a/b <= c/d, then (a + c)/(b + d) <= c/d. So, all you need to do is go through the whole array looking for the maximum fraction. This is a linear time operation as it avoids the bottleneck of sorting the whole array.
Here is the proof of the statement. Assume there exist 2 positive rational numbers a/b, c/d such that a/b <= c/d. Notice then, ad <= bc, which would mean that ad + cd <= bc + cd. This is equivalent to saying that (a + c)d <= c(b + d), which implies (a + c)/(b + d) <= c/d. Because of this, your subset sum (as you have defined it) is bounded by the maximum positive fraction in your array. So, all you need to do is find the maximum fraction in your array (call it maxP) and return max(maxP, 0), assuming an empty subset is allowed.
This looks like an variation on knapsack problem. Try to maximize the sum of k fractions ( take k items to maximize value ) and see if that exceeds c/d.
Also when calculating the value, use (a+b)/(c+d) and so on rather than summing up their individual values.

Dividing N items in p groups

You are given N total number of item, P group in which you have to divide the N items.
Condition is the product of number of item held by each group should be max.
example N=10 and P=3 you can divide the 10 item in {3,4,3} since 3x3x4=36 max possible product.
You will want to form P groups of roughly N / P elements. However, this will not always be possible, as N might not be divisible by P, as is the case for your example.
So form groups of floor(N / P) elements initially. For your example, you'd form:
floor(10 / 3) = 3
=> groups = {3, 3, 3}
Now, take the remainder of the division of N by P:
10 mod 3 = 1
This means you have to distribute 1 more item to your groups (you can have up to P - 1 items left to distribute in general):
for i = 0 up to (N mod P) - 1:
groups[i]++
=> groups = {4, 3, 3} for your example
Which is also a valid solution.
For fun I worked out a proof of the fact that it in an optimal solution either all numbers = N/P or the numbers are some combination of floor(N/P) and ceiling(N/P). The proof is somewhat long, but proving optimality in a discrete context is seldom trivial. I would be interested if anybody can shorten the proof.
Lemma: For P = 2 the optimal way to divide N is into {N/2, N/2} if N is even and {floor(N/2), ceiling(N/2)} if N is odd.
This follows since the constraint that the two numbers sum to N means that the two numbers are of the form x, N-x.
The resulting product is (N-x)x = Nx - x^2. This is a parabola that opens down. Its max is at its vertex at x = N/2. If N is even this max is an integer. If N is odd, then x = N/2 is a fraction, but such parabolas are strictly unimodal, so the closer x gets to N/2 the larger the product. x = floor(N/2) (or ceiling, it doesn't matter by symmetry) is the closest an integer can get to N/2, hence {floor(N/2),ceiling(N/2)} is optimal for integers.
General case: First of all, a global max exists since there are only finitely many integer partitions and a finite list of numbers always has a max. Suppose that {x_1, x_2, ..., x_P} is globally optimal. Claim: given and i,j we have
|x_i - x_ j| <= 1
In other words: any two numbers in an optimal solution differ by at most 1. This follows immediately from the P = 2 lemma (applied to N = x_i + x_ j).
From this claim it follows that there are at most two distinct numbers among the x_i. If there is only 1 number, that number is clearly N/P. If there are two numbers, they are of the form a and a+1. Let k = the number of x_i which equal a+1, hence P-k of the x_i = a. Hence
(P-k)a + k(a+1) = N, where k is an integer with 1 <= k < P
But simple algebra yields that a = (N-k)/P = N/P - k/P.
Hence -- a is an integer < N/P which differs from N/P by less than 1 (k/P < 1)
Thus a = floor(N/P) and a+1 = ceiling(N/P).
QED

Finding a certain set of numbers from a list

I am working on this project where the user inputs a list of numbers. I put these numbers in an array. I need to find a set of numbers with a given length whose sum is divisible by 5.
For example, if the list is 9768014, and the length required is 6, then the output would be 987641.
What algorithm do I need to find that set of numbers?
You can solve this by dynamic programming. Let f(n,m,k) be the largest index between 1 and n of the number in a subset of indices {1,2,....,n} that gives a sum of k mod 5 that uses m numbers. (It's possible that f(n,m,k) = None). You can compute f(n+1,m,k) and f(n,m+1,k) if you know the values of f(N,M,k) for all N <= n + 1 and M < m and also for all N <= n and M < m + 1 and also for N=n,M=m, and all k = 0,1,2,3,4. If you ever find that f(n,m,0) has a solution where m is your desired number of numbers to use, then you're done. Also you don't have to compute f(N,M,k) for any M greater than your desired count of numbers to use. Total complexity is O(n*m) where n is the total count of numbers and m is the size of subset that you are trying to reach.

Resources