Program to find expected sum of subarrays of a given array by performing some operations
Suppose we have an array A whose size is n and two values p and q. We can perform these operations on A.
- Randomly select two indexes (l, r) where l < r, then exchange A[l] and A[r]
- Randomly select two indexes (l, r) where l < r, then reverse subarray of A form index l to r.
After performing first operation p number of times and the second operation q times, we randomly select two indices l & r where l < r and calculate the S = sum of all elements of the sub array A[l..r], then we have to find the expected value of S.
So, if the input is like A = [1,2,3] p = 1 q = 1, then the output will be 4.667 because
Step 1: we have three choices −
swap(0, 1) so the array will be 2 1 3
swap(0, 2) so the array will be 3 2 1
swap(1, 2) so the array will be 1 3 2
Step 2: we have three choices again for each outcome −
[2 1 3] to [1 2 3], [3 1 2], [2 3 1]
[3 2 1] to [2 3 1], [1 2 3], [3 1 2]
[1 3 2] to [3 1 2], [2 3 1], [1 2 3]
There are 9 possible arrays so probability is 1/9. So each of the 9 arrays will have 3 possible sums with equal probability. For an instance, [1 2 3], we can get 1+2, 2+3 and 1+2+3. And there are 27 outcome in total for this input, the expected value can be calculated by finding sum of all 27S and dividing it by 27.
To solve this, we will follow these steps −
- Define a function matmul() . This will take a, v, n
- toret := an array of size n and fill with 0
- for i in range 0 to n - 1, do
- for j in range 0 to n - 1, do
- toret[i] := toret[i] + a[i, j]*v[j]
- for j in range 0 to n - 1, do
- return toret
- From the main method, do the following:
- n := size of A
- temp := a new list
- swp := (n - 3) /(n - 1)
- swapvalp := ((swp^p)*(n - 1) + 1) /n
- swapvalm :=(1 - (swp^p)) /n
- rev := a new empty list
- dotv := a new empty list
- for i in range 0 to n - 1, do
- swaprow := a new empty list
- revrow := a new empty list
- for j in range 0 to n - 1, do
- insert swapvalm at the end of swaprow
- insert 2*(minimum of i, j, (n-i-1) and (n-j-1+1)/(n*(n - 1)) at the end of revrow
- swaprow := a new empty list
- revrow := a new empty list
- for j in range 0 to n - 1, do
- swaprow[i] := swapvalp
- revrow[i] := 1.0 - 2*((i + 1)*(n - i) - minimum of (i+1) and (n - i))/(n*(n-1))
- insert swaprow at the end of temp
- insert revrow at the end of rev
- insert 2*((i+1)*(n-i) - 1)/(n*(n-1)) at the end of dotv
- A := matmul(temp, A, n)
- for i in range 0 to q, do
- A := matmul(rev, A, n)
- tot := 0.0
- for i in range 0 to n, do
- tot := tot + dotv[i]*A[i]
- return tot
Example
Let us see the following implementation to get better understanding −
def matmul(a, v, n): toret = [0]*n for i in range(n): for j in range(n): toret[i] += a[i][j]*v[j] return toret def solve(A, p, q): n = len(A) temp = [] swp = (n - 3)/(n - 1) swapvalp = (pow(swp, p)*(n - 1) + 1)/n swapvalm = (1 - pow(swp, p))/n rev = [] dotv = [] for i in range(n): swaprow = [] revrow = [] for j in range(n): swaprow.append(swapvalm) revrow.append(2*(min(i, j, n - i - 1, n - j - 1) + 1)/(n*(n - 1))) swaprow[i] = swapvalp revrow[i] = 1.0 - 2*((i + 1)*(n - i) - min(i + 1, n - i))/(n*(n - 1)) temp.append(swaprow) rev.append(revrow) dotv.append(2*((i + 1)*(n - i) - 1)/(n*(n - 1))) A = matmul(temp, A, n) for _ in range(q): A = matmul(rev, A, n) tot = 0.0 for i in range(n): tot += dotv[i]*A[i] return tot A = [1,2,3] p = 1 q = 1 print(solve(A, p, q))
Input
[1,2,3], 1, 1
Output
0.0