I'm using Ruby, but for the purposes of this problem it doesn't really matter.
Let's say I have two different kinds of resources, the quantities of which are denoted by a and b. I can allocate d new resources, and since a and b are of equal cost and equal value to production, I can choose to allocate resources in whatever way is most profitable.
This might best be explained like so: (a + j) * (b + k) = c, where j + k = d. I want to maximize c by the best allocation of resources, with the understanding that the cost of the two different types of resources and their value to production are the same. All variables are positive integers, with a and b being greater than 0. Here's my naive brute force method:
def max_alloc(a, b, d)
max_j = 0
max_k = 0
max_c = 0
(0..d).each do |j|
k = d - j
c = (a + j) * (b + k)
if c > max_c
max_c = c
max_j = j
max_k = k
end
end
[max_j, max_k]
end
I'm hoping that there's some sort of mathematical or algorithmic "trick" I'm missing that will keep me from having to resort to brute force.
Do you really need an algorithm to do that?
This is a simple maximum/minimum optimization problem.
Now consider the equation
It is a function of j, so let's call it f(j):
You want to find j such that c = f(j) is maximum... so you want to study the sign of it's derivative
Now you can draw the table of signs
There you have it! A maximum for
this means the j, k pair you are looking for is
and for such values you'll have the maximum value of c:
In Ruby
def max_alloc(a, b, d)
j = (-a + b + d) / 2.0
j = j.round # round to prevent Float, explained at the end of this answer
if j < 0
j = 0 # prevent from negative values
elsif j > d
j = d # prevent from values greater than d
end
[j, d - j]
end
Or even shorter
def max_alloc(a, b, d)
j = ((-a + b + d) / 2.0).round
j = [0, [j, d].min].max # make sure j is in range 0..d
[j, d - j]
end
A one-liner too if you like
def max_alloc(a, b, d)
[[0, [((-a + b + d) / 2.0).round, d].min].max, d - [0, [((-a + b + d) / 2.0).round, d].min].max]
end
An in-depth look at the cases j < 0 and j > d
Let's start from the bounds that j must satisfy:
So j* is:
Now, since f(j) is always a parabola opened downward, the absolute maximum will be it's vertex, so, as discovered before:
But what if this point is outside the given range for j? You'll have to decide wheter to chose j* = 0, k* = d or j* = d, k* = 0.
Since f(j) is strictly increasing for j < j* and strictly descreasing for j > j*, the closer you get to j*, the greater would be f(j) value.
Therefore, if j* > d the choose j* = d, if j* < 0 then choose j = 0.
Here I show some plots just to see this in action:
Why j.round?
As you just learned f(j) is a parabola, and parabolas have an axis of symmetry. If j* is an integer, you are done, otherwise for what integer value is f(j) maximized? Well... for the integer value closest to the vertex; i.e., j.round.
Note: If a, b and d are integers, then j* can only be an integer or xxx.5. So f(j) would be the same for j.ceil and j.floor... You choose.
For given constants a and b, let
f(j,k) = (a + j) * (b + k)
We wish to maximize f(j,k) subject to three requirements:
j + k = d, for a given constant d
j >= 0
k >= 0
We can substitute out k (or j) to by replacing k with
k = d - j
This changes f to:
f(j) = (a + j) * (b + d - j)
= a*(b + d) + (b + d - a)*j -j**2
The problem is now to maximize f subject to:
0 <= j <= d
The second part of this inequality follows from k = d - j >= 0. If d = 0, j = k = 0 is the only solution that satisfies the requirement that the variables are non-negative. If d < 0 there is no feasible solution. These two cases should be checked for but I will assume d > 0.
We first set the derivative of f to zero and solve for j to determine where f's slope is zero:
f'(j) = b + d - a - 2*j = 0
so
j* = (b + d - a)/2
As the second derivative of f is
f''(j) = -2 < 0
we know f is concave, so j* is a maximum (rather than a minimum were it convex). Convex and concave functions are shown here1:
Consider the graph of the concave function. Values of j are on the horizontal axis. Since j* must be between 0 and d to be feasible (both variables have non-negative values), let the points a, c and b on the graph equal 0, j* and d, respectively.
There are three possibilities:
0 <= j* <= d, in which case that is a feasible solution (since k = d - j* >= 0).
j* < 0, in which case the largest feasible value of f is where j = 0.
j* > d, in which case the largest feasible value of f is where j = d.
Once the optimum value of j has been determined, k = d - j
Here are some examples.
Ex. 1: a = 2, b = 3, d = 5
j* = (b + d - a)/2 = (3 + 5 - 2)/2 = 3
Since 0 <= 3 <= 5, j = 3, k = 5 - 3 = 2 are the optimum values of j and k and f(3) = 25 is the optimum value.
Ex. 2: a = 6, b = 1, d = 3
j* = (b + d - a)/2 = (1 + 3 - 6)/2 = -1
Since -1 < 0, j = 0, k = 3 - 0 = 3 are the optimum values of j and k and f(0) = 24 is the optimum value.
Ex. 3: a = 2, b = 7, d = 3
j* = (b + d - a)/2 = (7 + 3 - 2)/2 = 4
Since 4 < 3, j = 3, k = 3 - 3 = 0 is the optimum value of j and f(3) = 35 is the optimum value.
If j and k must be integer-valued at the maximum value of f, we can assume a, b and d are integer-valued. (If a and b are not, a can be rounded up and b rounded down.) Let j* now be the value of j satisfying 0 <= j <= d for which is f(j) is a maximum (but j* is not necessarily an integer). Because f is concave, if j* is not integer, the optimal value of j is J*.floor if f(j*.floor) >= f(j*.ceil) and j*.ceil otherwise.
1 A function f is concave if, for all a and b, a < b, and all x, a <= x <= b, f(x) >= g(x), where g is the linear function having the property that g(a) = f(a) and g(b) = f(b).
Related
B is a subsequence of A if and only if we can turn A to B by removing zero or more element(s).
A = [1,2,3,4]
B = [1,4] is a subsequence of A.(Just remove 2 and 4).
B = [4,1] is not a subsequence of A.
Count all subsequences of A that satisfy this condition : A[i]%i = 0
Note that i starts from 1 not 0.
Example :
Input :
5
2 2 1 22 14
Output:
13
All of these 13 subsequences satisfy B[i]%i = 0 condition.
{2},{2,2},{2,22},{2,14},{2},{2,22},{2,14},{1},{1,22},{1,14},{22},{22,14},{14}
My attempt :
The only solution that I could came up with has O(n^2) complexity.
Assuming the maximum element in A is C, the following is an algorithm with time complexity O(n * sqrt(C)):
For every element x in A, find all divisors of x.
For every i from 1 to n, find every j such that A[j] is a multiple of i, using the result of step 1.
For every i from 1 to n and j such that A[j] is a multiple of i (using the result of step 2), find the number of B that has i elements and the last element is A[j] (dynamic programming).
def find_factors(x):
"""Returns all factors of x"""
for i in range(1, int(x ** 0.5) + 1):
if x % i == 0:
yield i
if i != x // i:
yield x // i
def solve(a):
"""Returns the answer for a"""
n = len(a)
# b[i] contains every j such that a[j] is a multiple of i+1.
b = [[] for i in range(n)]
for i, x in enumerate(a):
for factor in find_factors(x):
if factor <= n:
b[factor - 1].append(i)
# There are dp[i][j] sub arrays of A of length (i+1) ending at b[i][j]
dp = [[] for i in range(n)]
dp[0] = [1] * n
for i in range(1, n):
k = x = 0
for j in b[i]:
while k < len(b[i - 1]) and b[i - 1][k] < j:
x += dp[i - 1][k]
k += 1
dp[i].append(x)
return sum(sum(dpi) for dpi in dp)
For every divisor d of A[i], where d is greater than 1 and at most i+1, A[i] can be the dth element of the number of subsequences already counted for d-1.
JavaScript code:
function getDivisors(n, max){
let m = 1;
const left = [];
const right = [];
while (m*m <= n && m <= max){
if (n % m == 0){
left.push(m);
const l = n / m;
if (l != m && l <= max)
right.push(l);
}
m += 1;
}
return right.concat(left.reverse());
}
function f(A){
const dp = [1, ...new Array(A.length).fill(0)];
let result = 0;
for (let i=0; i<A.length; i++){
for (d of getDivisors(A[i], i+1)){
result += dp[d-1];
dp[d] += dp[d-1];
}
}
return result;
}
var A = [2, 2, 1, 22, 14];
console.log(JSON.stringify(A));
console.log(f(A));
I believe that for the general case we can't provably find an algorithm with complexity less than O(n^2).
First, an intuitive explanation:
Let's indicate the elements of the array by a1, a2, a3, ..., a_n.
If the element a1 appears in a subarray, it must be element no. 1.
If the element a2 appears in a subarray, it can be element no. 1 or 2.
If the element a3 appears in a subarray, it can be element no. 1, 2 or 3.
...
If the element a_n appears in a subarray, it can be element no. 1, 2, 3, ..., n.
So to take all the possibilities into account, we have to perform the following tests:
Check if a1 is divisible by 1 (trivial, of course)
Check if a2 is divisible by 1 or 2
Check if a3 is divisible by 1, 2 or 3
...
Check if a_n is divisible by 1, 2, 3, ..., n
All in all we have to perform 1+ 2 + 3 + ... + n = n(n - 1) / 2 tests, which gives a complexity of O(n^2).
Note that the above is somewhat inaccurate, because not all the tests are strictly necessary. For example, if a_i is divisible by 2 and 3 then it must be divisible by 6. Nevertheless, I think this gives a good intuition.
Now for a more formal argument:
Define an array like so:
a1 = 1
a2 = 1× 2
a3 = 1× 2 × 3
...
a_n = 1 × 2 × 3 × ... × n
By the definition, every subarray is valid.
Now let (m, p) be such that m <= n and p <= n and change a_mtoa_m / p`. We can now choose one of two paths:
If we restrict p to be prime, then each tuple (m, p) represents a mandatory test, because the corresponding change in the value of a_m changes the number of valid subarrays. But that requires prime factorization of each number between 1 and n. By the known methods, I don't think we can get here a complexity less than O(n^2).
If we omit the above restriction, then we clearly perform n(n - 1) / 2 tests, which gives a complexity of O(n^2).
X, Y and Z are three positive integers. I have to find value of a, b and c such that X^a * Y^b * Z^c is closest to some given number N and a+b+c is minimum (a, b and c are positive integers).
Edit: My current solution is to iterate over X, Y and Z raised to powers starting from 1. Compute the product of these terms, compare with previous best result and accordingly update the value of a, b and c. A python snippet of this approach is pasted below. I am assuming that X, Y and Z are integers greater than 1.
def foo(X, Y, Z, N):
res = a = b = c = -1
for i in range(1, int(math.log(N)/math.log(X))):
for j in range(1, int(math.log(N)/math.log(Y))):
for k in range(1, int(math.log(N)/math.log(Z))):
product = pow(X, i) * pow(Y, j) * pow(Z, k)
if product > N:
break
if product > res:
res = product
a = i
b = j
c = k
return a, b, c
This approach is giving me correct result for small values of X, Y and Z but I am not sure if it will work for all values. Is there anything I'm missing or any other approach with better complexity.
Your solution seems fine. You won't be doing that many iterations anyway because of how fast powers grow and reach N in log steps.
A few optimizations are that you dont have to compute the product every time. Have a single number and keep manipulating that value. (See code) This helps when dealing with large numbers in python.
Slightly Optimized Code :
def foo2(x, y, z, N):
a = b = c = -1
i = j = k = -1
maxProd = 1
curProd = 1
for i in range(1, N):
curProd *= x
for j in range(1, N):
curProd *= y
for k in range(1, N):
curProd *= z
if curProd > N:
break
if curProd > maxProd:
maxProd = curProd
a,b,c = i,j,k
curProd //= z**k
if curProd > N:
break
curProd //= y**j
if curProd > N:
break
curProd //= x**i
return a, b, c
Input :
x = 4
y = 7
z = 3
N = 21563163762572572574634215165164617645147157
Output :
(30, 22, 14)
Time Analysis :
Your Implementation : 82 ms
My Implementation : 14 ms
Worst Case :
I have been struggling through a dynamic programming exercise and I can't seem to get the hold of it. I'll write here the problem and also it's solution stating explicitly what I don't understand.
We are given 2 sequences u1,u2,...,un and d1,d2,...,dm and a matrix of dimensions n x m built of positive integers C=[cij]. A list of k pairs
((ui1, dj1),(ui2,dj2),...,(uik,djk)) is said to be non-intersecting if
i1 < 12 <..< ik and j1 < j2 <...< jk.
The "compatibility of a list" is said to be the compatibility of the sum of the pairs that it is made of, that is Ci1j1 + Ci2j2 + ... + Cikjk
Example :
Consider the matrix C = [Cij], so Cij = squared(i + j). Let i be
i = 1, 2, 3, j = 1, 2, 3, 4 and k = 2. Some lists of 2 non-intersecting pairs are these ((u1, d2),(u3, d3)) with a compatibility of 9 + 36 = 45,
((u2, d2),(u3, d4)), with compatibility 16 + 49 = 65, and ((u1, d1),(u2, d4)), with compatibility of 4 + 36 = 40. Some lists that are not non-intersecting are the following : ((u2, d2),(u3, d1)),((u1, d4),(u3, d3)),((u3, d2),(u2, d3))
Solution:
M(i, j, t) = maximum cost of t non-intersecting pairs taken from ui,...,un and dj,...dm
Recurrence equation :
M(i, j, t) = max {M(i + 1, j + 1, t − 1) + c(i, j), M(i, j + 1, t),M(i + 1, j, t).}
M(i, j, 0) = 0
M(i, j, t) = −∞, if t > min{n − i + 1, m − j + 1}
M(i, j, t) = 0, if i > n or j > m
I don't under the reccurrence very well and why do we assign −∞ to M(i, j, t) when t > min{n − i + 1, m − j + 1} but 0 when i > n or j > m
The solution is M(1, 1, k).
M(i, j, t) = max {M(i + 1, j + 1, t − 1) + c(i, j), M(i, j + 1, t),M(i + 1, j, t).}
= max
{
M(i+1, j+1, t-1) + c(i, j), <- we know the maximum cost of t-1
non-intersecting pairs taken from
i+1,...,n and j+1,...,m to which
we prepend the pair (i, j).
M(i, j+1, t), <- keep it at t elements and don't prepend anything,
and take the one containing elements from
i,...,n and j+1,...,m
M(i+1, j, t) <- same, but take elements from i+1,...,n and j,...,m
}
This covers all cases: either we prepend the current element and increase the length by 1 or we don't increase the length and take the maximum of the possibilities this (lack of) action entails. You might ask "but what about M(i+1,j+1,t)? that's also a valid possibility." It is, but it's covered by the two other cases: M(i+1,j,t) will check M(i+1,j+1,t) and return it if needed. You could add it yourself to the recurrence, it wouldn't be wrong, just redundant.
why do we assign −∞ to M(i, j, t) when t > min{n − i + 1, m − j + 1}
Because you cannot have a solution in that case. At step i, you can only pick n - i + 1 elements from the first sequence (because you already picked up to i). Same for j. If t > min{n - i + 1, m - j + 1}, then you will not be able to pick the needed number of elements from one of the lists, and you mark that with negative infinity.
but 0 when i > n or j > m
This is just to handle out of range errors. I'm not sure why they choose 0, I would choose negative infinity for this as well just for consistency, or just avoid it altogether by putting conditions in the implementation (if i + 1 >= n then ignore this branch, although you'll still need to return 0/-infinity if none of the branches are valid), but it doesn't really matter.
If you return 0 and the answer is negative, then you'll run into problems. Of course, for your problem, due to the way C is built, we cannot have a negative solution (because C contains squares of numbers, which are >= 0 always). So you could go with 0 instead of negative infinity in the first case as well.
Exercise: can you write a similar recurrence, but for which the solution is given by M(n, m, k)? Define it in words first, and then mathematically.
I need to traverse all pairs i,j with 0 <= i < n, 0 <= j < n and i < j for some positive integer n.
Problem is that I can only loop through another variable, say k. I can control the bounds of k. So the problem is to determine two arithmetic methods, f(k) and g(k) such that i=f(k) and j=g(k) traverse all admissible pairs as k traverses its consecutive values.
How can I do this in a simple way?
I think I got it (in Python):
def get_ij(n, k):
j = k // (n - 1) # // is integer (truncating) division
i = k - j * (n - 1)
if i >= j:
i = (n - 2) - i
j = (n - 1) - j
return i, j
for n in range(2, 6):
print n, sorted(get_ij(n, k) for k in range(n * (n - 1) / 2))
It basically folds the matrix so that it's (almost) rectangular. By "almost" I mean that there could be some unused entries on the far right of the bottom row.
The following pictures illustrate how the folding works for n=4:
and n=5:
Now, iterating over the rectangle is easy, as is mapping from folded coordinates back to coordinates in the original triangular matrix.
Pros: uses simple integer math.
Cons: returns the tuples in a weird order.
I think I found another way, that gives the pairs in lexicographic order. Note that here i > j instead of i < j.
Basically the algorithm consists of the two expressions:
i = floor((1 + sqrt(1 + 8*k))/2)
j = k - i*(i - 1)/2
that give i,j as functions of k. Here k is a zero-based index.
Pros: Gives the pairs in lexicographic order.
Cons: Relies on floating-point arithmetic.
Rationale:
We want to achieve the mapping in the following table:
k -> (i,j)
0 -> (1,0)
1 -> (2,0)
2 -> (2,1)
3 -> (3,0)
4 -> (3,1)
5 -> (3,2)
....
We start by considering the inverse mapping (i,j) -> k. It isn't hard to realize that:
k = i*(i-1)/2 + j
Since j < i, it follows that the value of k corresponding to all pairs (i,j) with fixed i satisfies:
i*(i-1)/2 <= k < i*(i+1)/2
Therefore, given k, i=f(k) returns the largest integer i such that i*(i-1)/2 <= k. After some algebra:
i = f(k) = floor((1 + sqrt(1 + 8*k))/2)
After we have found the value i, j is trivially given by
j = k - i*(i-1)/2
I'm not sure to understand exactly the question, but to sum up, if 0 <= i < n, 0 <= j < n , then you want to traverse 0 <= k < n*n
for (int k = 0; k < n*n; k++) {
int i = k / n;
int j = k % n;
// ...
}
[edit] I just saw that i < j ; so, this solution is not optimal since there's less that n*n necessary iterations ...
If we think of our solution in terms of a number triangle, where k is the sequence
1
2 3
4 5 6
7 8 9 10
11 12 13 14 15
...
Then j would be our (non zero-based) row number, that is, the greatest integer such that
j * (j - 1) / 2 < k
Solving for j:
j = ceiling ((sqrt (1 + 8 * k) - 1) / 2)
And i would be k's (zero-based) position in the row
i = k - j * (j - 1) / 2 - 1
The bounds for k are:
1 <= k <= n * (n - 1) / 2
Is it important that you actually have two arithmetic functions f(k) and g(k) doing this? Because you could first create a list such as
L = []
for i in range(n-1):
for j in range(n):
if j>i:
L.append((i,j))
This will give you all the pairs you asked for. Your variable k can now just run along the index of the list. For example, if we take n=5,
for x in L:
print(x)
gives us
(0,1), (0,2), (0,3), (0,4), (1,2), (1,3), (1,4), (2,3), (2,4), (3,4)
Suppose your have 2<=k<5 for example, then
for k in range(2, 5)
print L[k]
yields
(0,3), (0,4), (1,2)
I am having trouble understanding a solution to an algorithmic problem
In particular, I don't understand how or why this part of the code
s += a[i];
total += query(s);
update(s);
allows you to compute the total number of points in the lower left quadrant of each point.
Could someone please elaborate?
As an analogue for the plane problem, consider this:
For a point (a, b) to lie in the lower left quadrant of (x, y), a <
x & b < y; thus, points of the form (i, P[i]) lie in the lower left quadrant
of (j, P[j]) iff i < j and P[i] < P[j]
When iterating in ascending order, all points that were considered earlier lie on the left compared to the current (i, P[i])
So one only has to locate all P[j]s less that P[i] that have been considered until now
*current point refers to the point in consideration in the current iteration of the for loop that you quoted ie, (i, P[i])
Let's define another array, C[s]:
C[s] = Number of Prefix Sums of array A[1..(i - 1)] that amount to s
So the solution to #3 becomes the sum ... C[-2] + C[-1] + C[0] + C[1] + C[2] ... C[P[i] - 1], ie prefix sum of C[P[i]]
Use the BIT to store the prefix sum of C, thus defining query(s) as:
query(s) = Number of Prefix Sums of array A[1..(i - 1)] that amount to a value < s
Using these definitions, s in the given code gives you the prefix sum up to the current index i (P[i]). total builds the answer, and update simply adds P[i] to the BIT.
We have to repeat this method for all i, hence the for loop.
PS: It uses a data structure called a Binary Indexed Tree (http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=binaryIndexedTrees) for operations. If you aren't acquainted with it, I'd recommend that you check the link.
EDIT:
You are given a array S and a value X. You can split S into two disjoint subarrays such that L has all elements of S less than X, and H that has those that are greater than or equal to X.
A: All elements of L are less than all elements of H.
Any subsequence T of S will have some elements of L and some elements of H. Let's say it has p elements of L and q of H. When T is sorted to give T', all p elements of L appear before the q elements of H because of A.
Median being the central value is the value at location m = (p + q)/2
It is intuitive to think that having q >= p implies that the median lies in X, as a proof:
Values in locations [1..p] in T' belong to L. Therefore for the median to be in H, it's position m should be greater than p:
m > p
(p + q)/2 > p
p + q > 2p
q > p
B: q - p > 0
To computer q - p, I replace all elements in T' with -1 if they belong to L ( < X ) and +1 if they belong to H ( >= X)
T looks something like {-1, -1, -1... 1, 1, 1}
It has p times -1 and q times 1. Sum of T' will now give me:
Sum = p * (-1) + q * (1)
C: Sum = q - p
I can use this information to find the value in B.
All subsequences are of the form {A[i], A[i + 2], A[i + 3] ... A[j + 1]} since they are contiguous, To compute sum of A[i] to A[j + 1], I can compute the prefix sum of A[i] with P[i] = A[1] + A[2] + .. A[i - 1]
Sum of subsequence from A[i] to A[j] then can be computed as P[j] - P[i] (j is greater of j and i)
With C and B in mind, we conclude:
Sum = P[j] - P[i] = q - p (q - p > 0)
P[j] - P[i] > 0
P[j] > P[i]
j > i and P[j] > P[i] for each solution that gives you a median >= X
In summary:
Replace all A[i] with -1 if they are less than X and -1 otherwise
Computer prefix sums of A[i]
For each pair (i, P[i]), count pairs which lie to its lower left quadrant.