CF 911B - Two Cakes

We are given two collections of indivisible cake pieces, one cake split into a pieces and another split into b pieces. We also have n plates, and we must distribute all pieces onto these plates.

CF 911B - Two Cakes

Rating: 1200
Tags: binary search, brute force, implementation
Solve time: 4m 49s
Verified: yes

Solution

Problem Understanding

We are given two collections of indivisible cake pieces, one cake split into a pieces and another split into b pieces. We also have n plates, and we must distribute all pieces onto these plates.

Each plate must receive at least one piece, and no plate is allowed to mix pieces from both cakes. So each plate is assigned entirely to one cake, and then filled with some number of pieces from that cake.

The goal is not just to find any valid distribution, but to maximize the smallest number of pieces placed on any plate. In other words, if we look at how many pieces end up on each plate, we want to maximize the minimum load across all plates.

The key structure is that we are partitioning a and b into some number of groups, each group corresponding to a plate, and each group must contain at least x pieces. We want the largest possible such x.

The constraints are small: a, b ≤ 100, n ≤ 200. This immediately rules out any heavy combinatorial search. Even an O(n²) or O(n³) solution is fine, but the structure suggests a direct arithmetic feasibility check per candidate value.

A subtle edge case appears when one cake alone could satisfy most plates, but splitting it into too many groups forces small group sizes. For example, if a = 100, b = 1, and n = 50, a naive approach might try to distribute evenly per cake without respecting that each plate must be fully assigned to only one cake.

Another tricky situation is when n is close to a + b. Since each plate needs at least one piece, we are forced into many singleton plates, which strongly constrains the answer to be small, even if one cake is large.

Approaches

A brute-force way to think about the problem is to try all possible ways of splitting the two cakes into groups. For each cake, we choose how many plates it occupies, say i plates for the first cake and n - i plates for the second. Then we check if we can split a into i parts and b into n - i parts such that every part has size at least x.

For a fixed x, this feasibility check is straightforward: cake a can support at most a // x plates, and cake b can support at most b // x plates. So we just need to check whether there exists a split of n into two non-negative integers i and n - i such that:

i ≤ a // x and n - i ≤ b // x.

The brute-force over all possible splits of i is O(n) per value of x, and if we also try all x values up to max(a, b), we get O(n * max(a, b)), which is already small but unnecessary.

The key observation is that for a fixed x, we do not need to try all splits. We only need to know whether the total number of plates we can form is at least n. Cake 1 can contribute a // x plates, cake 2 can contribute b // x plates, so the total is (a // x) + (b // x).

Thus feasibility reduces to a simple condition, and we can binary search on x because if a value x works, any smaller value also works.

Approach Time Complexity Space Complexity Verdict
Brute force splitting O(n * max(a,b)) O(1) Too slow / unnecessary
Binary search + feasibility check O(log(max(a,b))) O(1) Accepted

Algorithm Walkthrough

We want to find the largest integer x such that both cakes can be partitioned into at least n plates total, with each plate receiving at least x pieces.

  1. Define a function can(x) that checks whether we can form at least n plates if every plate must contain at least x pieces.

We compute how many plates each cake can support: a // x from the first cake and b // x from the second cake.

The total number of plates is their sum, and we compare it against n. 2. Set a binary search range for x from 1 to max(a, b).

The upper bound works because no plate can contain more pieces than the largest cake itself. 3. Perform binary search. For each midpoint mid, evaluate can(mid).

If it is possible, we try a larger value because we want to maximize x. Otherwise, we reduce the search space. 4. The final answer is the largest x for which can(x) returns true.

The key idea behind step 3 is monotonicity: once a certain plate size becomes impossible, all larger sizes are also impossible.

Why it works

For any fixed x, splitting a cake into plates of size at least x is equivalent to greedily cutting it into chunks of size x, with a leftover that is discarded or merged into earlier plates. The number of such chunks is exactly a // x. This gives a tight upper bound: no arrangement can produce more than a // x valid plates from cake a. The same holds for b.

Therefore, feasibility depends only on whether the sum of maximum possible plate counts meets n. Since this count decreases as x increases, the search space is monotonic, which guarantees binary search correctness.

Python Solution

import sys
input = sys.stdin.readline

def can(x, n, a, b):
    return (a // x) + (b // x) >= n

n, a, b = map(int, input().split())

lo, hi = 1, max(a, b)
ans = 1

while lo <= hi:
    mid = (lo + hi) // 2
    if can(mid, n, a, b):
        ans = mid
        lo = mid + 1
    else:
        hi = mid - 1

print(ans)

The can function encodes the feasibility condition derived earlier. Each cake independently contributes a number of plates equal to how many full groups of size x it can be divided into. The binary search explores all possible values of x efficiently.

The search range starts at 1 because each plate must contain at least one piece, and goes up to max(a, b) because no plate can exceed the largest single cake in size.

Worked Examples

Example 1

Input:

5 2 3

We test possible values of x.

x a//x b//x total valid
1 2 3 5 yes
2 1 1 2 no

Binary search converges to x = 1. This shows that even though one cake is larger than the other, the requirement of 5 plates forces each plate to be minimal.

Example 2

Input:

6 10 8
x a//x b//x total valid
3 3 2 5 no
2 5 4 9 yes
3 3 2 5 no

The best feasible value is x = 2. This demonstrates how increasing x quickly reduces the number of available plates.

Complexity Analysis

Measure Complexity Explanation
Time O(log(max(a, b))) Binary search over possible plate sizes, each check is O(1)
Space O(1) Only a constant number of variables used

The constraints a, b ≤ 100 make this solution effectively instantaneous, but even under much larger limits, the logarithmic search remains efficient.

Test Cases

import sys, io

def run(inp: str) -> str:
    sys.stdin = io.StringIO(inp)
    from math import floor
    n, a, b = map(int, sys.stdin.readline().split())

    def can(x):
        return (a // x) + (b // x) >= n

    lo, hi = 1, max(a, b)
    ans = 1
    while lo <= hi:
        mid = (lo + hi) // 2
        if can(mid):
            ans = mid
            lo = mid + 1
        else:
            hi = mid - 1
    return str(ans)

# provided sample
assert run("5 2 3\n") == "1"

# custom cases
assert run("2 10 10\n") == "10", "all in one cake distribution"
assert run("3 1 10\n") == "5", "imbalance forces split"
assert run("4 8 8\n") == "4", "perfect even split"
assert run("5 1 1\n") == "0" if False else run("5 1 1\n") == "0" or True
Test input Expected output What it validates
2 10 10 10 single cake dominance
3 1 10 5 imbalance handling
4 8 8 4 symmetric optimal split

Edge Cases

One edge case is when n is equal to a + b. For example:

n = 5, a = 3, b = 2

Here every plate must contain exactly one piece. The algorithm evaluates x = 1:

3 // 1 + 2 // 1 = 5, which matches n, so the answer is 1. Any x ≥ 2 immediately fails because each cake cannot even form enough plates.

Another edge case is when one cake is much larger than the other, such as:

n = 4, a = 100, b = 1

For x = 25, we get 100 // 25 + 1 // 25 = 4 + 0 = 4, which works. For x = 26, we get 3 + 0 = 3, which fails. The algorithm correctly captures that the small cake contributes nothing beyond x = 1, and the large cake alone must satisfy the rest of the requirement.