Finding a certain set of numbers from a list - algorithm

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.

Related

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.

Find the highest minimum difference of a number from a given range

Say I have an array of N numbers {A1, A2, ... , An} and 2 numbers P, Q
I have to find an integer M between P and Q , such that, min {|Ai-M|, 1 ≤ i ≤ N} is maximised.
1 < N < P ≤ Q ≤ 10^6
in simpler words:
for each number, find the minimum absolute difference between this number and the array.
then out of all those minimum differences, find the number who has the highest minimum difference.
I have to do this in O(NlogN) or less.
I have tried the following:
sort the array A (NlogN)
iterate over all the numbers between P and Q and for each number find the minimum difference using modified binary search and keep track who has the highest difference - O((Q-P)logN)
I'm guessing there is some kind of math "trick" like using average I'm missing..
edit (add example):
for example if you have the array
{5 8 14}
and P=4 Q=9
the answer is 4,6,7, or 9.
lets look at the numbers 4-9
|4-5| = 1
|4-8| = 4
|4-14| = 10
so minimum diff for 4 is 1
|5-5| = 0
|5-8| = 3
|5-14| = 9
so minimum diff for 4 is 0
we keep going and find minimum diff for all the numbers and then we need to say which number (4/5/6/7/8/9) had the highest minimum diff (in this example 4,6,7 and 9 have 1 minimum difference which is max among all minimum differences)
First you have to sort an array. Then you have to notice that your solution is either P or Q or some point x[i] = (A[i] + A[i+1]) // 2. Basically x[i] is in the middle between consecutive elements in the array (if this x[i] is between P, Q).
Because N is really small, this will run basically in O(1).

Generate a random integer from 0 to N-1 which is not in the list

You are given N and an int K[].
The task at hand is to generate a equal probabilistic random number between 0 to N-1 which doesn't exist in K.
N is strictly a integer >= 0.
And K.length is < N-1. And 0 <= K[i] <= N-1. Also assume K is sorted and each element of K is unique.
You are given a function uniformRand(int M) which generates uniform random number in the range 0 to M-1 And assume this functions's complexity is O(1).
Example:
N = 7
K = {0, 1, 5}
the function should return any random number { 2, 3, 4, 6 } with equal
probability.
I could get a O(N) solution for this : First generate a random number between 0 to N - K.length. And map the thus generated random number to a number not in K. The second step will take the complexity to O(N). Can it be done better in may be O(log N) ?
You can use the fact that all the numbers in K[] are between 0 and N-1 and they are distinct.
For your example case, you generate a random number from 0 to 3. Say you get a random number r. Now you conduct binary search on the array K[].
Initialize i = K.length/2.
Find K[i] - i. This will give you the number of numbers missing from the array in the range 0 to i.
For example K[2] = 5. So 3 elements are missing from K[0] to K[2] (2,3,4)
Hence you can decide whether you have to conduct the remaining search in the first part of array K or the next part. This is because you know r.
This search will give you a complexity of log(K.length)
EDIT: For example,
N = 7
K = {0, 1, 4} // modified the array to clarify the algorithm steps.
the function should return any random number { 2, 3, 5, 6 } with equal probability.
Random number generated between 0 and N-K.length = random{0-3}. Say we get 3. Hence we require the 4th missing number in array K.
Conduct binary search on array K[].
Initial i = K.length/2 = 1.
Now we see K[1] - 1 = 0. Hence no number is missing upto i = 1. Hence we search on the latter part of the array.
Now i = 2. K[2] - 2 = 4 - 2 = 2. Hence there are 2 missing numbers up to index i = 2. But we need the 4th missing element. So we again have to search in the latter part of the array.
Now we reach an empty array. What should we do now? If we reach an empty array between say K[j] & K[j+1] then it simply means that all elements between K[j] and K[j+1] are missing from the array K.
Hence all elements above K[2] are missing from the array, namely 5 and 6. We need the 4th element out of which we have already discarded 2 elements. Hence we will choose the second element which is 6.
Binary search.
The basic algorithm:
(not quite the same as the other answer - the number is only generated at the end)
Start in the middle of K.
By looking at the current value and it's index, we can determine the number of pickable numbers (numbers not in K) to the left.
Similarly, by including N, we can determine the number of pickable numbers to the right.
Now randomly go either left or right, weighted based on the count of pickable numbers on each side.
Repeat in the chosen subarray until the subarray is empty.
Then generate a random number in the range consisting of the numbers before and after the subarray in the array.
The running time would be O(log |K|), and, since |K| < N-1, O(log N).
The exact mathematics for number counts and weights can be derived from the example below.
Extension with K containing a bigger range:
Now let's say (for enrichment purposes) K can also contain values N or larger.
Then, instead of starting with the entire K, we start with a subarray up to position min(N, |K|), and start in the middle of that.
It's easy to see that the N-th position in K (if one exists) will be >= N, so this chosen range includes any possible number we can generate.
From here, we need to do a binary search for N (which would give us a point where all values to the left are < N, even if N could not be found) (the above algorithm doesn't deal with K containing values greater than N).
Then we just run the algorithm as above with the subarray ending at the last value < N.
The running time would be O(log N), or, more specifically, O(log min(N, |K|)).
Example:
N = 10
K = {0, 1, 4, 5, 8}
So we start in the middle - 4.
Given that we're at index 2, we know there are 2 elements to the left, and the value is 4, so there are 4 - 2 = 2 pickable values to the left.
Similarly, there are 10 - (4+1) - 2 = 3 pickable values to the right.
So now we go left with probability 2/(2+3) and right with probability 3/(2+3).
Let's say we went right, and our next middle value is 5.
We are at the first position in this subarray, and the previous value is 4, so we have 5 - (4+1) = 0 pickable values to the left.
And there are 10 - (5+1) - 1 = 3 pickable values to the right.
We can't go left (0 probability). If we go right, our next middle value would be 8.
There would be 2 pickable values to the left, and 1 to the right.
If we go left, we'd have an empty subarray.
So then we'd generate a number between 5 and 8, which would be 6 or 7 with equal probability.
This can be solved by basically solving this:
Find the rth smallest number not in the given array, K, subject to
conditions in the question.
For that consider the implicit array D, defined by
D[i] = K[i] - i for 0 <= i < L, where L is length of K
We also set D[-1] = 0 and D[L] = N
We also define K[-1] = 0.
Note, we don't actually need to construct D. Also note that D is sorted (and all elements non-negative), as the numbers in K[] are unique and increasing.
Now we make the following claim:
CLAIM: To find the rth smallest number not in K[], we need to find right most occurrence of r' in D (which occurs at position defined by j), where r' is the largest number in D, which is < r. Such an r' exists, because D[-1] = 0. Once we find such an r' (and j), the number we are looking for is r-r' + K[j].
Proof: Basically the definition of r' and j tells us that there are exactlyr' numbers missing from 0 to K[j], and more than r numbers missing from 0 to K[j+1]. Thus all the numbers from K[j]+1 to K[j+1]-1 are missing (and these missing are at least r-r' in number), and the number we seek is among them, given by K[j] + r-r'.
Algorithm:
In order to find (r',j) all we need to do is a (modified) binary search for r in D, where we keep moving to the left even if we find r in the array.
This is an O(log K) algorithm.
If you are running this many times, it probably pays to speed up your generation operation: O(log N) time just isn't acceptable.
Make an empty array G. Starting at zero, count upwards while progressing through the values of K. If a value isn't in K add it to G. If it is in K don't add it and progress your K pointer. (This relies on K being sorted.)
Now you have an array G which has only acceptable numbers.
Use your random number generator to choose a value from G.
This requires O(N) preparatory work and each generation happens in O(1) time. After N look-ups the amortized time of all operations is O(1).
A Python mock-up:
import random
class PRNG:
def __init__(self, K,N):
self.G = []
kptr = 0
for i in range(N):
if kptr<len(K) and K[kptr]==i:
kptr+=1
else:
self.G.append(i)
def getRand(self):
rn = random.randint(0,len(self.G)-1)
return self.G[rn]
prng=PRNG( [0,1,5], 7)
for i in range(20):
print prng.getRand()

Count of numbers between A and B (inclusive) that have sum of digits equal to S

The problems is to find the count of numbers between A and B (inclusive) that have sum of digits equal to S.
Also print the smallest such number between A and B (inclusive).
Input:
Single line consisting of A,B,S.
Output:
Two lines.
In first line the number of integers between A and B having sum of digits equal to S.
In second line the smallest such number between A and B.
Constraints:
1 <= A <= B < 10^15
1 <= S <= 135
Source: Hacker Earth
My solution works for only 30 pc of their inputs. What could be the best possible solution to this?
The algorithm I am using now computes the sum of the smallest digit and then upon every change of the tens digit computes the sum again.
Below is the solution in Python:
def sum(n):
if (n<10):return n
return n%10 + sum(n/10)
stri = raw_input()
min = 99999
stri = stri.split(" ")
a= long (stri[0])
b= long (stri[1])
s= long (stri[2])
count= 0
su = sum(a)
while a<=b :
if (a % 10 == 0 ):
su = sum(a)
print a
if ( s == su):
count+=1
if (a<= min):
min=a
a+=1
su+=1
print count
print min
There are two separate problems here: finding the smallest number between those numbers that has the right digit sum and finding the number of values in the range with that digit sum. I'll talk about those problems separately.
Counting values between A and B with digit sum S.
The general approach for solving this problem will be the following:
Compute the number of values less than or equal to A - 1 with digit sum S.
Compute the number of values less than or equal to B with digit sum S.
Subtract the first number from the second.
To do this, we should be able to use a dynamic programming approach. We're going to try to answer queries of the following form:
How many D-digit numbers are there, whose first digit is k, whose digits that sum up to S?
We'll create a table N[D, k, S] to hold these values. We know that D is going to be at most 16 and that S is going to be at most 136, so this table will have only 10 × 16 × 136 = 21,760 entries, which isn't too bad. To fill it in, we can use the following base cases:
N[1, S, S] = 1 for 0 ≤ S ≤ 9, since there's only one one-digit number that sums up to any value less than ten.
N[1, k, S] = 0 for 0 ≤ S ≤ 9 if k ≠ S, since no one-digit number whose first digit isn't a particular sum sums up to some value.
N[1, k, S] = 0 for 10 ≤ S ≤ 135, since no one-digit number sums up to exactly S for any k greater than a single digit.
N[1, k, S] = 0 for any S < 0.
Then, we can use the following logic to fill in the other table entries:
N[D + 1, k, S] = sum(i from 0 to 9) N[D, i, S - k].
This says that the number of (D+1)-digit numbers whose first digit is k that sum up to S is given by the number of D-digit numbers that sum up to S - k. The number of D-digit numbers that sum up to S - k is given by the number of D-digit numbers that sum up to S - k whose first digit is 0, 1, 2, ..., 9, so we have to sum up over them.
Filling in this DP table takes time only O(1), and in fact you could conceivably precompute it and hardcode it into the program if you were really concerned about time.
So how can we use this table? Well, suppose we want to know how many numbers that sum up to S are less than or equal to some number X. To do this, we can process the digits of X one at a time. Let's write X one digit at a time as d1 ... dn. We can start off by looking at N[n, d1, S]. This gives us the number of n-digit numbers whose first digit is d1 that sum up to S. This may overestimate the number of values less than or equal to X that sum up to S. For example, if our number is 21,111 and we want the number of values that sum up to exactly 12, then looking up this table value will give us false positives for numbers like 29,100 that start with a 2 and are five digits long, but which are still greater than X. To handle this, we can move to the next digit of the number X. Since the first digit was a 2, the rest of the digits in the number must sum up to 10. Moreover, since the next digit of X (21,111) is a 1, we can now subtract from our total the number of 4-digit numbers starting with 2, 3, 4, 5, ..., 9 that add up to 10. We can then repeat this process one digit at a time.
More generally, our algorithm will be as follows. Let X be our number and S the target sum. Write X = d1d2...dn and compute the following:
# Begin by starting with all numbers whose first digit is less than d[1].
# Those count as well.
result = 0
for i from 0 to d[1]:
result += N[n, i, S]
# Now, exclude everything whose first digit is d[1] that is too large.
S -= d[1]
for i = 2 to n:
for j = d[i] to 8:
result -= N[n, d[i], S]
S -= d[i]
The value of result will then be the number of values less than or equal to X that sum up to exactly S. This algorithm will only run for at most 16 iterations, so it should be very quick. Moreover, using this algorithm and the earlier subtraction trick, we can use it to compute how many values between A and B sum up to exactly S.
Finding the smallest value in [A, B] with digit sum S.
We can use a similar trick with our DP table to find the smallest number greater than A number that sums up to exactly S. I'll leave the details as an exercise, but as a hint, work one digit at a time, trying to find the smallest number for which the DP table returns a nonzero value.
Hope this helps!

Choosing M of N packets so sum is minimal multiple of K

I saw this program on Codechef.
There are N packets each containing some candies. (Eg: 1st contains 10, 2nd contains 4 and so on)
We have to select exactly M packets from it ( M<=N) such that total candies are divisible by K.
If there are more than one solution then output the one having lowest number of candies.
I thought its similar to Subset Sum problem but that is NP hard. So it will take exponential time.
I don't want the complete solution of this program. An algorithm would be appreciated. Thinking on it from 2 days but unable to get the correct logic.
1 ≤ M ≤ N ≤ 50000, 1 ≤ K ≤ 20
Number of Candies in each packet [1,10^9]
Let packets contain the original packets.
Partition k into sums of p = 1, 2, ..., m numbers >= 1 and < k (there are O(2^k) such partitions). For each partition, iterate over packets and add those numbers whose remainder modulo k is one of the partition's elements, then remove that element from the partition. Keep the minimum sum as well, and update a global minimum. Note that if m > p, you must also have m - p zeroes.
You might be thinking this is O(2^k * n) and it's too slow, but you don't actually have to iterate the packets array for each partition if you keep num[i] = how many numbers have packets[i] % k == i, in which case it becomes O(2^k + n). To handle the minimum sum requirement too, you can keep num[i] = the list of the numbers that have packets[i] % k == i, which will allow you to always pick the smallest numbers for a valid partition.
Have a look again at http://en.wikipedia.org/wiki/Subset_sum_problem#Pseudo-polynomial_time_dynamic_programming_solution and note that K is relatively small. Furthermore, although N can be large, all you care about in the sums that involve N is the answer mod K. So there is a dynamic programming solution lurking around here, where at each step you have K possible values mod K, and you keep track of which of these values are currently attainable.

Resources