Algorithm to find maximum of combinations of arrays - algorithm

I have n finite arrays A[n], and the elements in those arrays are ordered pair (p,r) where 0 < p < 1 and r is a real number.
For instance,A[n][elements][0] = p,A[n][elements][1] = r
Let C = {p[1]*p[2] *...*p[n] * (r[1] + ...+ r[n]): where (p[i],r[i]) are in distinct arrays from A[n]} and I would like to find the maximum/minimum m elements of it.
Is there any algorithm that has order of any combinations of m and n, but not the actual size of the arrays in A[n]?
Example: say n = 2, m = 2, A[1] = {(0.23,91.2),(0.45,-31.7),(0.32,60.5)} and A[2] = {(0.12,150.3),(0.26,13.3),(0.33,200.3),(0.29,-23.4)}.
The 2 maximum is given by 0.32*0.33*(60.5+200.3)=27.54 and 0.45*0.33*(-31.7+200.3)=25.04.
The 2 minimum is given by 0.45*0.28*(-31.7+-23.4)=-7.19 and 0.45*0.26*(-31.7+13.3)=-2.15.

Related

Pseudocode Sum & Division Algorithm

"Given a list L of n numbers, take the sum of absolute values divided by the number of elements in L." How can I do this?
This is what I have so far
start
Get values for list L and n
INDEX = 1
while (INDEX ≤ n) do
Read: n;
Set sum = 0;
for i = 1 to n by 1 do
Set sum = sum + i
It is not clear - whether n is known prior L
read n
read n values in L
sum = 0
for i = 1 to n by 1 do //assuming 1-based list indexing
sum = sum + Abs(L[i])
av = sum / n

Sort array with range of values in O(n)

There's an array A[1, ..., n], and its known that every 1 <= l <= n then A[l] in {1,2,...,n^5}.
How can I find an algroithm which sorts this in O(n) ?
Imagine representing the values in A[i] in Base-n system. Then each number becomes a five-digit n-ary number, meaning that you can sort the entire array with five applications of Radix Sort, with "radix" of n.
Compute the value of each "digit" x in a number k as follows:
dx = (k / (n x)) % n
where / denotes integer division.
sort list of integers a using base-N radix sort,
also this applies for a simple list
def rsort(a,N):
if a:
bins = [ [],[],[],[],[] ]
m = max(a)
r = 1
while m > r:
for e in a:
bins[(e/r)%N].append(e)
r = r * N
a = []
for i in range(N):
a.extend(bins[i])
bins[i] = []
return a

DP solution to find if there is group of numbers which is divisible by M

Let's say we have number N, such that 0 < N <= 10^6 and 2 <= M <= 10^3 and array of N elements a[1], a[2], ... a[N] (0<= a[i] <=10^9)\
Now we have to check if we can choose group of numbers from the array such that their sum will be divisible by M, and output "YES" or "NO".
Here are two examples:
N = 3, M =5 a={1,2,3} answer="YES"
N = 4, M = 6 a={3,1,1,3} answer="YES"
thanks in advance.
C++ solution.
//declare dp array of boolean values of size M
bool dp[M] = {0}; // init with fasle values
for(int i = 0; i < N; i++) {
bool ndp[M] = {0}; // init temporary boolean array
ndp[a[i] % M] = 1; // add a subset with one a[i] element
for(int j = 0; j < M; j++)
if(dp[j]) { // if we may find a subset of elements with sum = j (modulo M)
ndp[j] = 1; // copy existing values
ndp[(j + a[i]) % M] = 1; // extend the subset with a[i], which will give a sum = j + a[i] (modulo M)
}
// copy from ndp to dp before proceeding to the next element of a
for(int j = 0; j < M; j++) dp[j] = ndp[j];
}
//check dp[0] for the answer
The algorithm complexity will be O(N*M) which in your case is O(109)
Edit: Added ndp[a[i] % M] = 1; line in order to make dp[j] ever become nonzero.
There might be another alternative O(M * M * log(M) + N) solution which in your case is O(107) (but with big constant).
Notice that if substitute each a[i] with a[i] % M the problem statement does not change. Lets count the number of a[i] elements that give specific remainder j after division on M. If for some remainder j we found k elements in a then we can generate the following sums of subsets (that may produce unique remainder)
j, 2 * j % M, 3 * j % M ... k * j % M
Example: let M = 6 and for remainder 2 we found 5 elements in a. Then we have the following unique sums of subsets:
2 % 6, 2 * 2 % 6, 3 * 2 % 6, 4 * 2 % 6, 5 * 2 % 6
which is 0, 2, 4
store this information in boolean form {1, 0, 1, 0, 1, 0}
At most we have M such groups that produce M-size bool array of possible remainders.
Next we need to find all possible subsets that may appear if we will take elements of different groups. Lets say we merge two bool remainder arrays a and b if we can introduce new array c that will contain all possible remainder sums of elements from subset of a and b. Naive approach will require us to make two nested loops over a and b giving O(M2) merge time complexity.
We may reduce complexity to O(M * log(M)) using Fast Fourier Transform algo. Each bool array has a polynomial Σ ai*xi where coefficients ai are taken from bool array. If we want to merge two array we may just multiply their polynomials.
Overall complxity is O(M2 * log(M)) as we need to make M such merges.

Sum of products of elements of all subarrays of length k

An array of length n is given. Find the sum of products of elements of the sub-array.
Explanation
Array A = [2, 3, 4] of length 3.
Sub-array of length 2 = [2,3], [3,4], [2,4]
Product of elements in [2, 3] = 6
Product of elements in [3, 4] = 12
Product of elements in [2, 4] = 8
Sum for subarray of length 2 = 6+12+8 = 26
Similarly, for length 3, Sum = 24
As, products can be larger for higher lengths of sub-arrays calculate in modulo 1000000007.
What is an efficient way for finding these sums for subarrays of all possible lengths, i.e., 1, 2, 3, ......, n where n is the length of the array.
There is rather simple way:
Construct product of terms (1 + A[i] * x):
P = (1 + A[0] * x) * (1 + A[1] * x) * (1 + A[2] * x)...*(1 + A[n-1] * x)
If we open the brackets, then we'll get polynomial
P = 1 + B[1] * x + B[2] * x^2 + ... + B[n] * x^n
Kth coefficient, B[k], is equal to the sum of products of sets with length K - for example, B[n] = A[0]*A[1]*A[2]*..A[n-1], B[2] = A[0]*A[1] + A[0]*A[2] + ... + A[n-2]*A[n-1] and so on.
So to find sum of products of all possible sets, we have to find value of polynomial P for x = 1, then subtract 1 to remove leading 0th term. If we don't want to take into consideration single-element sets, then subtract B1 = sum of A[i].
Example:
(1+2)(1+3)(1+4) = 60
60 - 1 = 59
59 - (2 + 3 + 4) = 50 = 24 + 26 - as your example shows
We first create a recursive relation. Let f(n, k) be the sum of all products of sub-arrays of length k from an array a of length n. The base cases are simple:
f(0, k) = 0 for all k
f(n, 0) = 1 for all n
The second rule might seem a little counter-intuitive, but 1 is the zero-element of multiplication.
Now we find a recursive relation for f(n+1, k). We want the product of all subarrays of size k. There are two types of subarrays here: the ones including a[n+1] and the ones not including a[n+1]. The sum of the ones not including a[n+1] is exactly f(n, k). The ones including a[n+1] are exactly all subarrays of length k-1 with a[n+1] added, so their summed product is a[n+1] * f(n, k-1).
This completes our recurrence relation:
f(n, k) = 0 if n = 0
= 1 if k = 0
= f(n-1, k) + a[n] * f(n-1, k-1) otherwise
You can use a neat trick to use very limited memory for your dynamic programming, because function f only depends on two earlier values:
int[] compute(int[] a) {
int N = a.length;
int[] f = int[N];
f[0] = 1;
for (int n = 1; n < N; n++) {
for (int k = n; k >= 1; k--) {
f[k] = (f[k] + a[n] * f[k-1]) % 1000000007;
}
}
return f;
}

Sum of continuous sequences

Given an array A with N elements, I want to find the sum of minimum elements in all the possible contiguous sub-sequences of A. I know if N is small we can look for all possible sub sequences but as N is upto 10^5 what can be best way to find this sum?
Example: Let N=3 and A[1,2,3] then ans is 10 as Possible contiguous sub sequences {(1),(2),(3),(1,2),(1,2,3),(2,3)} so Sum of minimum elements = 1 + 2 + 3 + 1 + 1 + 2 = 10
Let's fix one element(a[i]). We want to know the position of the rightmost element smaller than this one located to the left from i(L). We also need to know the position of the leftmost element smaller than this one located to the right from i(R).
If we know L and R, we should add (i - L) * (R - i) * a[i] to the answer.
It is possible to precompute L and R for all i in linear time using a stack. Pseudo code:
s = new Stack
L = new int[n]
fill(L, -1)
for i <- 0 ... n - 1:
while !s.isEmpty() && s.top().first > a[i]:
s.pop()
if !s.isEmpty():
L[i] = s.top().second
s.push(pair(a[i], i))
We can reverse the array and run the same algorithm to find R.
How to deal with equal elements? Let's assume that a[i] is a pair <a[i], i>. All elements are distinct now.
The time complexity is O(n).
Here is a full pseudo code(I assume that int can hold any integer value here, you should
choose a feasible type to avoid an overflow in a real code. I also assume that all elements are distinct):
int[] getLeftSmallerElementPositions(int[] a):
s = new Stack
L = new int[n]
fill(L, -1)
for i <- 0 ... n - 1:
while !s.isEmpty() && s.top().first > a[i]:
s.pop()
if !s.isEmpty():
L[i] = s.top().second
s.push(pair(a[i], i))
return L
int[] getRightSmallerElementPositions(int[] a):
R = getLeftSmallerElementPositions(reversed(a))
for i <- 0 ... n - 1:
R[i] = n - 1 - R[i]
return reversed(R)
int findSum(int[] a):
L = getLeftSmallerElementPositions(a)
R = getRightSmallerElementPositions(a)
int res = 0
for i <- 0 ... n - 1:
res += (i - L[i]) * (R[i] - i) * a[i]
return res
If the list is sorted, you can consider all subsets for size 1, then 2, then 3, to N. The algorithm is initially somewhat inefficient, but an optimized version is below. Here's some pseudocode.
let A = {1, 2, 3}
let total_sum = 0
for set_size <- 1 to N
total_sum += sum(A[1:N-(set_size-1)])
First, sets with one element:{{1}, {2}, {3}}: sum each of the elements.
Then, sets of two element {{1, 2}, {2, 3}}: sum each element but the last.
Then, sets of three elements {{1, 2, 3}}: sum each element but the last two.
But this algorithm is inefficient. To optimize to O(n), multiply each ith element by N-i and sum (indexing from zero here). The intuition is that the first element is the minimum of N sets, the second element is the minimum of N-1 sets, etc.
I know it's not a python question, but sometimes code helps:
A = [1, 2, 3]
# This is [3, 2, 1]
scale = range(len(A), 0, -1)
# Take the element-wise product of the vectors, and sum
sum(a*b for (a,b) in zip(A, scale))
# Or just use the dot product
np.dot(A, scale)

Resources