from functools import lru_cache
class Solution:
def soupServings(self, n: int) -> float:
if n > 5000:
return 1.0
@lru_cache(None)
def dp(a, b):
if a <= 0 and b <= 0:
return 0.5
if a <= 0:
return 1.0
if b <= 0:
return 0.0
return 0.25 * (
dp(a-100, b) +
dp(a-75, b-25) +
dp(a-50, b-50) +
dp(a-25, b-75)
)
return dp(n, n)
class Solution {
public:
double soupServings(int N) {
if (N > 5000) return 1.0;
vector<vector<double>> memo(200, vector<double>(200, -1.0));
function<double(int,int)> dp = [&](int a, int b) {
if (a <= 0 && b <= 0) return 0.5;
if (a <= 0) return 1.0;
if (b <= 0) return 0.0;
if (memo[a][b] > -0.5) return memo[a][b];
return memo[a][b] = 0.25 * (
dp(a-4, b) +
dp(a-3, b-1) +
dp(a-2, b-2) +
dp(a-1, b-3)
);
};
int n = (N + 24) / 25;
return dp(n, n);
}
};
class Solution {
public double soupServings(int N) {
if (N > 5000) return 1.0;
int n = (N + 24) / 25;
Double[][] memo = new Double[n + 1][n + 1];
return dp(n, n, memo);
}
private double dp(int a, int b, Double[][] memo) {
if (a <= 0 && b <= 0) return 0.5;
if (a <= 0) return 1.0;
if (b <= 0) return 0.0;
if (memo[a][b] != null) return memo[a][b];
memo[a][b] = 0.25 * (
dp(a - 4, b, memo) +
dp(a - 3, b - 1, memo) +
dp(a - 2, b - 2, memo) +
dp(a - 1, b - 3, memo)
);
return memo[a][b];
}
}
var soupServings = function(N) {
if (N > 5000) return 1.0;
const memo = {};
function dp(a, b) {
if (a <= 0 && b <= 0) return 0.5;
if (a <= 0) return 1.0;
if (b <= 0) return 0.0;
let key = a + ',' + b;
if (memo[key] !== undefined) return memo[key];
memo[key] = 0.25 * (
dp(a - 4, b) +
dp(a - 3, b - 1) +
dp(a - 2, b - 2) +
dp(a - 1, b - 3)
);
return memo[key];
}
let n = Math.ceil(N / 25);
return dp(n, n);
};
n
milliliters. At each turn, you randomly choose one of four possible serving combinations (each with equal probability) to serve from the soups:
0 <= n <= 10^9
n
efficientlyn
. This brute-force approach is clearly infeasible for large values of n
.
n
by dividing by 25, greatly reducing the state space. For very large n
, the probability approaches 1, so we can use an early cutoff for efficiency.
n
by 25 and round up. This reduces the problem size.n
: If n
is large (e.g., above 5000), the answer is very close to 1.0, so we can return 1.0 directly for efficiency.n
is based on the problem's probabilistic behavior and required precision.n = 50
n = ceil(50 / 25) = 2
. So both Soup A and B start with 2 units.
dp(2, 2)
:
dp(-2,2)
→ A is empty, B is not. Probability = 1.0dp(-1,1)
→ A is empty, B is not. Probability = 1.0dp(0,0)
→ Both empty. Probability = 0.5dp(1,-1)
→ B is empty, A is not. Probability = 0.0ans = 0.25 * (1.0 + 1.0 + 0.5 + 0.0) = 0.25 * 2.5 = 0.625
n = 50
is 0.625
.
n
(n > 5000), we shortcut and return 1.0 directly, making the solution very efficient.n
leverages the problem's probabilistic behavior to deliver fast, accurate results. The solution is elegant because it combines mathematical insight with algorithmic optimization for both correctness and efficiency.