Maximize the coins using K moves
Last Updated :
24 Feb, 2024
Given an integer N, the task is to maximize the coins which we can collect using K moves. In one move, we can perform one of the following operations:
- Type 1: Add N coins to our collection (N remains unchanged).
- Type 2: Add X to N, where X is the last digit of N.
Example:
Input: N = 1, K = 3
Output: 4
Explanation: The following operations are performed to maximize the number of coins collected.
- Perform Type 1 operation, N = 1 + 1 = 2
- Perform Type 1 operation N = 2 + 2 = 4
- Perform Type 2 operation, add N = 4 coins to our collection, total coins collected = 4
Input: N = 11, K = 3
Output: 33
Explanation: The following operations are performed to maximize the number of coins.
- Perform Type 2 operation, add N = 11 coins to our collection, total coins collected = 11.
- Perform Type 2 operation, add N = 11 coins to our collection, total coins collected = 22.
- Perform Type 2 operation, add N = 11 coins to our collection, total coins collected = 33.
Approach:
The solution is based on the greedy observation. So, the optimal strategy is to add bonuses first and then get the discount. This is because the more bonuses you have, the larger the discount you can get. if we keep performing operation 2, the last digit of s will cycle through the digits 2, 4, 8, 6. This leads to the formula for the answer:
ans=(s+20x)*(k-4x)
Here’s a simpler explanation of above formula:
- We start with a number s.
- Each time you perform operation 2, the last digit of s changes. If we keep performing operation 2, the last digit of s will cycle through the digits 2, 4, 8, 6.
- Each complete cycle through 2, 4, 8, 6 adds 20 to s (since 2+4+8+6 = 20).
- x represents the number of complete cycles.
- So, (s + 20x) gives us the total number of bonuses after x complete cycles.
- We can perform a total of k operations. If we use 4x operations for the cycles (since each cycle consists of 4 operations), we have (k – 4x) operations left.
- These remaining operations are used to add the total number of bonuses to the answer. So, (s + 20x) * (k – 4x) gives us the maximum possible value of the answer.
This is a parabolic equation, and its maximum can be found using the formula for the vertex of a parabola or by ternary search. The bisector of the parabola is (5k-s)/40. we can calculate the answer for each case where the last digit is 2, 4, 8, 6, and take the maximum value.
Notes:
- If the last digit of s is 5, you can perform operation 2 at most once.
- If the last digit of s is an odd number, you need to perform operation 2 once before you can enter the cycle.
Step-by-step approach:
- Declare variables lowerBound, upperBound, temp, and result.
- Initialize result to the product of numCoins and numMoves.
- Add the remainder when numCoins is divided by 10 to numCoins.
- Decrement numMoves.
- Update result with the maximum of the current result and the product of numCoins and numMoves.
- Check if numCoins is not divisible by 10.
- Calculate lowerBound as -1 and upperBound as numMoves / 4.
- Use binary search to find the optimal number of cycles.
- Update temp with the optimal number of cycles.
- Update result with the maximum of the current result and the product of (numCoins + temp * 20) and (numMoves – temp * 4).
- Add the remainder when numCoins is divided by 10 to numCoins.
- Decrement numMoves.
- Return the final value of result.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
long long max( long long a, long long b)
{
return a > b ? a : b;
}
int solve( int numCoins, int numMoves)
{
long long lowerBound, upperBound, temp, result;
int remainder;
result = numCoins * numMoves;
numCoins += numCoins % 10;
numMoves--;
result = max(result, numCoins * numMoves);
if (numCoins % 10 != 0) {
lowerBound = -1, upperBound = numMoves / 4;
while (upperBound - lowerBound > 1) {
temp = (lowerBound + upperBound) / 2;
if ((numCoins + temp * 20)
* (numMoves - temp * 4)
< (numCoins + (temp + 1) * 20)
* (numMoves - (temp + 1) * 4))
lowerBound = temp;
else
upperBound = temp;
}
temp = upperBound;
result = max(result, (numCoins + temp * 20)
* (numMoves - temp * 4));
numCoins += numCoins % 10;
numMoves--;
}
return result;
}
int main()
{
long long n = 1, k = 3;
cout << solve(n, k);
return 0;
}
|
Java
class GFG {
static long solve( long numCoins, long numMoves)
{
long lowerBound, upperBound, temp, result;
long remainder;
result = numCoins * numMoves;
numCoins += numCoins % 10 ;
numMoves--;
result = Math.max(result, numCoins * numMoves);
if (numCoins % 10 != 0 ) {
lowerBound = - 1 ;
upperBound = numMoves / 4 ;
while (upperBound - lowerBound > 1 ) {
temp = (lowerBound + upperBound) / 2 ;
if ((numCoins + temp * 20 )
* (numMoves - temp * 4 )
< (numCoins + (temp + 1 ) * 20 )
* (numMoves - (temp + 1 ) * 4 ))
lowerBound = temp;
else
upperBound = temp;
}
temp = upperBound;
result = Math.max(result,
(numCoins + temp * 20 )
* (numMoves - temp * 4 ));
numCoins += numCoins % 10 ;
numMoves--;
}
return result;
}
public static void main(String[] args)
{
long n = 1 , k = 3 ;
System.out.println(solve(n, k));
}
}
|
Python3
def solve(numCoins, numMoves):
result = numCoins * numMoves
numCoins + = numCoins % 10
numMoves - = 1
result = max (result, numCoins * numMoves)
if numCoins % 10 ! = 0 :
lowerBound = - 1
upperBound = numMoves / / 4
while upperBound - lowerBound > 1 :
temp = (lowerBound + upperBound) / / 2
if (numCoins + temp * 20 ) * (numMoves - temp * 4 ) < (numCoins + (temp + 1 ) * 20 ) * (numMoves - (temp + 1 ) * 4 ):
lowerBound = temp
else :
upperBound = temp
temp = upperBound
result = max (result, (numCoins + temp * 20 ) * (numMoves - temp * 4 ))
numCoins + = numCoins % 10
numMoves - = 1
return result
n, k = 1 , 3
print (solve(n, k))
|
C#
using System;
public class Program
{
public static long Max( long a, long b)
{
return a > b ? a : b;
}
public static int Solve( int numCoins, int numMoves)
{
long lowerBound, upperBound, temp, result;
result = numCoins * numMoves;
numCoins += numCoins % 10;
numMoves--;
result = Max(result, numCoins * numMoves);
if (numCoins % 10 != 0)
{
lowerBound = -1;
upperBound = numMoves / 4;
while (upperBound - lowerBound > 1)
{
temp = (lowerBound + upperBound) / 2;
if ((numCoins + temp * 20) * (numMoves - temp * 4) < (numCoins + (temp + 1) * 20) * (numMoves - (temp + 1) * 4))
lowerBound = temp;
else
upperBound = temp;
}
temp = upperBound;
result = Max(result, (numCoins + temp * 20) * (numMoves - temp * 4));
numCoins += numCoins % 10;
numMoves--;
}
return ( int )result;
}
public static void Main()
{
long n = 1, k = 3;
Console.WriteLine(Solve(( int )n, ( int )k));
}
}
|
Javascript
function solve(numCoins, numMoves) {
let lowerBound, upperBound, temp, result;
let remainder;
result = numCoins * numMoves;
numCoins += numCoins % 10;
numMoves--;
result = Math.max(result, numCoins * numMoves);
if (numCoins % 10 !== 0) {
lowerBound = -1;
upperBound = Math.floor(numMoves / 4);
while (upperBound - lowerBound > 1) {
temp = Math.floor((lowerBound + upperBound) / 2);
if ((numCoins + temp * 20) * (numMoves - temp * 4) < (numCoins + (temp + 1) * 20) * (numMoves - (temp + 1) * 4)) {
lowerBound = temp;
} else {
upperBound = temp;
}
}
temp = upperBound;
result = Math.max(result, (numCoins + temp * 20) * (numMoves - temp * 4));
numCoins += numCoins % 10;
numMoves--;
}
return result;
}
const n = 1;
const k = 3;
console.log(solve(n, k));
|
Time Complexity: O(log k) due to the binary search.
Auxiliary Space: O(1)
Share your thoughts in the comments
Please Login to comment...