Codeforces Round #255 "Modifying matrix" solution(Div-1 B)? - algorithm

I was trying to solve the "DZY Loves Modification" problem from Round #255 of CodeForces.
Problem link:
http://codeforces.com/contest/446/problem/B.
I am getting wrong answers for the system test cases.
My approach is as follows:
Construct two max-heaps - one heap for storing the row totals and
one for the column totals
Store two variables - rowReductionValue and colReductionValue -
these variables store the value that should be subtracted before
using a row or column's total sum.
For each iteration, choose the entry with maximum value from the
rowSum and colSum heaps
If a row is chosen, the row's total is added to the result and then
the row total is reduced by P * (number_of_columns)
After this, each column's value reduces by P. So, this P is
added to colReductionValue.
An analogous approach is used if a column is chosen.
This approach results in wrong answers.
I am sorry if I was not clear in explaining my approach, I wanted it to be as concise as possible.
Any light on the right approach or the flaw with this approach is much appreciated.
The code is below:
long long getMaxResult(int rows, int cols, int reductionValue, int K)
{
vector<long long> rowSums, colSums;
long long rowReductionValue = 0, colReductionValue = 0, result = 0;
for(int row = 0; row < rows; ++row)
{
long long sum = 0;
for(int col = 0; col < cols; ++col)
{
sum += a[row][col];
}
rowSums.push_back(sum);
}
for(int col = 0; col < cols; ++col)
{
long long sum = 0;
for(int row = 0; row < rows; ++row)
{
sum += a[row][col];
}
colSums.push_back(sum);
}
make_heap(rowSums.begin(), rowSums.end());
make_heap(colSums.begin(), colSums.end());
for(int k = 0; k < K; ++k)
{
pop_heap(rowSums.begin(), rowSums.end());
long long rowMax = rowSums.back();
rowSums.pop_back();
pop_heap(colSums.begin(), colSums.end());
long long colMax = colSums.back();
colSums.pop_back();
if(rowMax - rowReductionValue >= colMax - colReductionValue)
{
result += rowMax - rowReductionValue;
rowMax -= reductionValue * cols;
colReductionValue += reductionValue;
}
else
{
result += colMax - colReductionValue;
colMax -= reductionValue * rows;
rowReductionValue += reductionValue;
}
rowSums.push_back(rowMax);
push_heap(rowSums.begin(), rowSums.end());
colSums.push_back(colMax);
push_heap(colSums.begin(), colSums.end());
}
return result;
}
Thanks-

I'll walk you through the Greedy-Brute Force concept that I used to approach this problem:
If p = 0, apparently the best choice is choosing the row or column which can give greatest pleasure value each time.
Let's ignore p first, then we can get a greatest number ans using previous statement. Now if we choose rows for i times, choose column for k-i times, ans should be ansi - ((k-i) X i X p).
So we could enumerate i from 0 to k and calculate ansi - ((k-i) X i X p) each time, max{ansi - ((k-i) X i X p)} is the maximum possible pleasure value DZY could get.
Let ai be the maximum pleasure value we can get after choosing i rows and bi be the maximum pleasure value we can get after choosing i columns. Then ansi = ai+bk-i. We can use two priority queues to calculate ai and bi quickly.
Good luck!

Related

Given a matrix, cell is call good cell if row divides column

Given a n*m matrix, a cell is called good cell if row number (i) divides column number (j)
Example :
2*3 matrix => cells are {1,1}, {1,2}, {1,3}, {2,1}, {2,2}, {2,3} from which good cells can be defined as {1,1}, {1,2}, {1,3}, {2,2}
So the output is 4
I have figure out the logic for this, row 1 has all cells as good cells, row 2 has m/2 good cells, row 3 has m/3 good cells. (I am using just the integer dividend)
m/1 + m/2 + m/3 + ........ + m/n;
For which my code looks like =>
long count=1;
long answer = 0;
while(count<=n){
answer=answer + m/count;
count++;
}
But this code is getting timed out when I am submitting my solution. Need help to find better approach for this.
PS: Coding challenge is already over.
Try this one,
for(int i = 0 ; i < n; i++)
{
for(int j = 0; j < m; j += i) // j += i will save unwanted loops
{
// rest of your logic
}
}
As the value of i gets higher and higher nested loop will become more efficient
edit
The below code will be more efficient & correct than above. Now nested loop starts with the value of i instead of 0
for(int i = 0 ; i < n; i++)
{
for(int j = i; j < m; j += i) //j = i & j += i will save unwanted loops
{
// rest of your logic
}
}
as noted by n pronouns m this post incorrect since it only considers the case n==m
You may have a look at the Dirichlet divisor problem
One attempt is the formula of Benoit Cloitre:
(below octave implem)
function s = sumit(n)
s = 0;
for i = 1:n
s += floor(n/i);
end
end
n = 1e6
expect = sumit(n)
%A006218
u = floor(sqrt(n));
res = 2*sum(floor(n./(1:u))) - u^2
Where you avoid summing quite some terms.

Interview Question on Algorithms regarding Matrices

You are provided with an N*M matrix containing Integer values. Your task is to select one integer from each row such that the sum of these integers is maximum. However, you are not allowed to select two integers from adjacent rows in the same column.
How can I do this problem in less than O(N^M) (or O(M^N))?
I came up with two possible solutions: 1. using recursion, 2. using DP.
1. Using Recursion
I think you already have this solution. I made a recursive function that goes through each row in matrix and calls recursion for each column. As you mentioned, the time complexity would be O(M^N) where N is the number of rows and M is the number of columns.
int getMaxSum(int[][] matrix) {
return getMax(matrix, 0, -1);
}
int getMax(int[][] matrix, int row, int prevCol) {
if (row >= matrix.length) return 0;
int result = Integer.MIN_VALUE;
for (int i = 0; i < matrix[row].length; i++) {
if (i == prevCol) continue;
int sum = getMax(matrix, row+1, i) + matrix[row][i];
result = Math.max(result, sum);
}
return result;
}
2. Using DP
Instead of recursively going through all rows and columns, I can use DP to keep track of maximum sum for each column up to a certain row. For example, DP[r][c] can have a maximum possible sum at column c up to row r. To implement this, I need to go through all rows and columns in the input matrix, and at each index, I also need to go through maximum possible sums at previous row (excluding the same column). This would result in time complexity of O(N*M^2) where N is the number of rows and M is the number of columns.
int getMaxSum(int[][] matrix) {
if (matrix.length == 0) return 0;
int[][] maxSumsDP = new int[matrix.length+1][matrix[0].length];
for (int r = 1; r <= matrix.length; r++) {
for (int c = 0; c < matrix[r-1].length; c++) {
int maxPrev = Integer.MIN_VALUE;
for (int i = 0; i < maxSumDP[r-1].length; i++) {
if (i == c) continue;
maxPrev = Math.max(maxPrev, maxSumsDP[r-1][i]);
}
maxSumsDP[r][c] = maxPrev + matrix[r-1][c];
}
}
int result = maxSumsDP[maxSumsDP.length-1][0];
for (int i = 1; i < maxSumsDP[maxSumsDP.length-1].length; i++) {
result = Math.max(result, maxSumsDP[maxSumsDP.length-1][i]);
}
return result;
}

Find the subarray within an array (containing at least TWO number) which has the largest sum

Find the subarray within an array (containing at least TWO number) which has the largest sum.
For example, given the array [-2,-1,-3,-4,-1],
the contiguous subarray [-2,-1] has the largest sum = -3.
try to do it in O(n) time
Followup, if input is stream, how to solve it
public int maxSubArray(int[] nums) {}
For an Array of size (N). Let us call it A
You can create another array B where you will store the sum so Far.
Now traverse through the parent Array.
int max = Integer.MIN;
B[0] = A[0];
for(i=1;i<A.length;i++)
{
if(A[i] > 0){
B[i]=B[i-1] + A[i];
}else if(A[i]+B[i-1] > max){
B[i] = A[i]+B[i-1]
max = A[i]+B[i-1]
}
else{
B[i] = A[i];
}
Now the max number in Array B has the max possible sum of the consecutive sub Array but you don't know the Sub Array.
You can use Kadane's Algorithm in modified fashion.
You can find Kadane' Algorithm here. (You will store the ends of the subarray too).
How can we modify it?
-> Just keep in track of the window size you are taking i.e. RIGHT-LEFT>=1
I think this should help for all set of numbers including negative.
Still for all negative numbers (which you can check in an O(n) go). Just loop FROM o to N : maximum = max(arr[i]+arr[i+1],maximum);
Just to ensure if the case gets covered.
Something like this should work:
int maxvalue = int.MIN_VALUE;
for (int i = 0; i < N; i++)
for (int j = i + 1; j < N; j++) {
int value = 0;
for (int x = i; x <= j; x++)
value += array[x];
if (value > maxvalue)
maxvalue = value;
}
return maxvalue;

Dynamic programming based zigzag puzzle

I found this interesting dynamic programming problem where it's required to re-order a sequence of integers in order to maximize the output.
Steve has got N liquor bottles. Alcohol quantity of ith bottle is given by A[i]. Now he wants to have one drink from each of the bottles, in such a way that the total hangover is maximised.
Total hangover is calculated as follow (Assume the 'alcohol quantity' array uses 1-based indexing) :
int hangover=0 ;
for( int i=2 ; i<=N ; i++ ){
hangover += i * abs(A[i] - A[i-1]) ;
}
So, obviously the order in which he drinks from each bottle changes the Total hangover. He can drink the liquors in any order but not more than one drink from each bottle. Also once he starts drinking a liquor he will finish that drink before moving to some other liquor.
Steve is confused about the order in which he should drink so that the hangover is maximized. Help him find the maximum hangover he can have, if he can drink the liquors in any order.
Input Format :
First line contain number of test cases T. First line of each test case contains N, denoting the number of fruits. Next line contain N space separated integers denoting the sweetness of each fruit.
2
7
83 133 410 637 665 744 986
4
1 5 9 11
I tried everything that I could but I wasn't able to achieve a O(n^2) solution. By simply calculating the total hangover over all the permutations has a O(n!) time complexity. Can this problem be solved more efficiently?
Thanks!
My hunch: use a sort of "greedy chaining algorithm" instead of DP.
1) find the pair with the greatest difference (O(n^2))
2) starting from either, find successively the next element with the greatest difference, forming a sort of "chain" (2 x O(n^2))
3) once you've done it for both you'll have two "sums". Return the largest one as your optimal answer.
This greedy strategy should work because the nature of the problem itself is greedy: choose the largest difference for the last bottle, because this has the largest index, so the result will always be larger than some "compromising" alternative (one that distributes smaller but roughly uniform differences to the indices).
Complexity: O(3n^2). Can prob. reduce it to O(3/2 n^2) if you use linked lists instead of a static array + boolean flag array.
Pseudo-ish code:
int hang_recurse(int* A, int N, int I, int K, bool* F)
{
int sum = 0;
for (int j = 2; j <= N; j++, I--)
{
int maxdiff = 0, maxidx;
for (int i = 1; i <= N; i++)
{
if (F[i] == false)
{
int diff = abs(F[K] - F[i]);
if (diff > maxdiff)
{
maxdiff = diff;
maxidx = i;
}
}
}
K = maxidx;
F[K] = true;
sum += maxdiff * I;
}
return sum;
}
int hangover(int* A, int N)
{
bool* F = new bool[N];
int maxdiff = 0;
int maxidx_i, maxidx_j;
for (int j = 2; j <= N; j++, I--)
{
for (int i = 1; i <= N; i++)
{
int diff = abs(F[j] - F[i]);
if (diff > maxdiff)
{
maxdiff = diff;
maxidx_i = i;
maxidx_j = j;
}
}
}
F[maxidx_i] = F[maxidx_j] = true;
int maxsum = max(hang_recurse(A, N, N - 1, maxidx_i, F),
hang_recurse(A, N, N - 1, maxidx_j, F));
delete [] F;
return maxdiff * N + maxsum;
}

Dynamic Programming: Find the rectangle in a grid that has the largest sum

I came across the following Dynamic Programming problem.
You have a grid of integers (so including negative numbers). Find the rectangle that has the largest sum of numbers.
Any idea how to do it for a whole matrix?
I solved it for a single array, so I pretty much followed what longest increasing subsequnce does, but only for contiguous numbers.
def array_largest_block(sequence)
len = sequence.size
parents = [nil]*len
my_largest = sequence
largest = sequence.max
for index in (1...len)
if my_largest[index] < my_largest[index] + my_largest[index - 1]
my_largest[index] = my_largest[index] + my_largest[index - 1]
parents[index] = index - 1
largest = [largest, my_largest[index]].max
end
end
end_index_of_largest_block = my_largest.find_index(largest)
i = end_index_of_largest_block
res = []
res << sequence[i]
while !parents[i].nil?
i = parents[i]
res << sequence[i]
end
return {l_sum: largest, start: i, end: end_index_of_largest_block}
end
So My thinking is,
find the sum of each square in the matrix (just 1x1 squares)
save the max for a possible answer
Run the same thing starting from smallest possible rectangle and calculate all of them until you find the max. Which is the DB part.
Any ideas? Or if you guys don't knwo the exact solution, which DP type algorithm should i look at?
This can be done in O(N^3), where N is the size of the matrix.
You basically choose the left and right column of the rectangle and then scan through the rows in linear time(using precomputed sums).
int totalBestSum = -10000000;
for (int leftCol = 1; leftCol <= N; leftCol++)
for (int rightCol = leftCol; rightCol <= N; rightCol++)
{
int curSum = 0, curBestSum = -10000000;
for (int row = 1; row <= N; row++) {
int rowSum = sumBetween(leftCol, rightCol, row);
curSum += rowSum;
if (curSum > curBestSum) curBestSum = curSum;
if (curSum < 0) curSum = 0;
}
if (curBestSum > totalBestSum) totalBestSum = curBestSum;
}
sumBetween is a function returning the sum of the numbers on a particular row between two columns. It can be implemented in constant time, using precomputed sums.
int sumBetween(int leftCol, int rightCol, int row)
{
return sum[row][rightCol] - sum[row][leftCol - 1];
}
To compute the sum array:
for (int row = 1; row <= N; row++)
for (int col = 1; col <= N; col++)
sum[row][col] = sum[row][col - 1] + matrix[row][col];
Seems like a duplicate, but still, look here: Getting the submatrix with maximum sum?
It is possible to do in O(N^3).
And why on earth do you use the 'NP-complete' tags?:D

Resources