Brute force, Greedy
We are given an integer S represented in a 7-segment display. Add some segments or digits into it to create the as large number as possible not larger than M.
Since we want to maximize the number, it is always optimal to make S contain the same number of digits as M (assume that we allow leading zeros). Hence, there are two steps in the solution:
- Add some digits before S and some digits after S in such a way that the resulting length is equal to M's length.
- Add some segments in such a way to maximize the resulting number.
We can perform all possible ways of the first step using brute force. For each intermediate result after the first step, the second step can be performed using greedy. Finally, we output the largest resulting number over all ways.
First, let’s introduce a compatibility matrix valid[i][j] = whether digit i can be transformed into digit j by adding some segments. The value of each cell of the matrix can be computed by hand. Here are the values:
\ 0123456789 +---------- 0|1000000010 1|1101100111 2|0010000010 3|0001000011 4|0000100011 5|0000011011 6|0000001010 7|1001000111 8|0000000010 9|0000000011
Let’s go through the steps in more details.
Let |X| be the number of digits of X. As mentioned before, in an optimal solution the number of digits of M and S must be equal. There are exactly |M| - |S| + 1 possible ways to add new digits. For example, suppose S = 89375 and M = 9247529. Then, there are 3 ways:
- Add 0 digits before S and 2 digits after S: 89375XX
- Add 1 digits before S and 1 digits after S: X89375X
- Add 2 digits before S and 0 digits after S: XX89375
Here, the new digits are represented by X’s for convenience. Let’s call the new integer after adding some digits as S*.
Note that the restriction that the resulting number must not have leading zeros is so that we cannot have the length resulting number is greater than |M| but that difference of length consists of all leading zeros. If that is allowed, then for test case like S = 0, M = 9 we can have 09 as the resulting number, hence making the problem trickier. Since we have in our solution that |S| = |M|, we can safely ignore that restriction.
For each possible intermediate result of Step 1, we must replace each X by an actual digit and optionally add some segments to the existing digits. We can use a greedy method here. We will iterate S* from the most significant digit through the least significant digit. For each digit, we try to transform it into the largest digit, while maintaining that the final result is not greater than M. This way, it can be proved that the result is the largest possible.
When iterating the digits from the most significant digit through the least significant digit, the choice of the current digit depends on the current prefixes of M and S*. Suppose we are now considering the i-th most significant digit. The current state would be like this:
M = Pp... S* = Qq... ^ i-th most significant digit
where p and q are M anp S*'s i-th most significant digits, respectively, while P and Q are M and S*'s current prefixes, respectively. The (i+1)-th through the |M|-th digits are not considered yet. For example, let M = 9247529, the currently built S* = 89375XX, and i = 4, then the current state is:
M = 9247... S* = 8937... ^ 4-th most significant digit
where P = 924, Q = 893, p = 7, and q = 7.
For each state, i.e. for each step in the iteration, there are 2 possibilities to maintain that the resulting number is not greater than M:
q > p. Here, Q must be strictly less than P because otherwise the resulting number would be greater than M.
q ≤ p. Here, Q must be less than or equal to P.
From the above explanation, let’s maintain two values while iterating the digits:
- prefix_less = the maximum prefix of S* that is strictly less than the corresponding prefix of M, or -1 if there is no such prefix
- prefix_equal = the corresponding prefix of M, or -1 if we cannot have equal prefix for M and S*
We update the two values after each step in the iteration. In the end, we choose the iteration that yields the maximum value. Please consult the following pseudocode for more details. The time complexity of this solution is O(|M|^2).
// returns the maximum possible resulting number // if we align the first digit of S with the k-th digit of M // or -1 if it is impossible. function solve(M, S, k): prefix_less = -1 prefix_equal = 0 for i = 1; i ≤ |M|; i++: // if the resulting number must be greater than M, then impossible if prefix_less == -1 and prefix_equal = -1 return -1 // update prefix_less for d = 9; d ≥ 0; d--: // if we cannot transform the digit, continue. if i ≥ k and i ≤ k + |S| - 1 and not valid[S[i - k + 1]][d]: continue // found the largest valid digit. // if the new digit is greater than the current digit, use prefix_less if d > M[i]: if prefix_less != -1: prefix_less = prefix_less * 10 + d // if the new digit is not greater than the current digit, use either prefix_less or prefix_equal else if prefix_less != -1: if max(prefix_less, prefix_equal) != -1: prefix_less = max(prefix_less, prefix_equal) * 10 + d break // update prefix_equal if i ≥ k and i ≤ k + |S| - 1 and not valid[S*[i - k + 1]][M[i]]: prefix_equal = -1 else prefix_equal = prefix_equal * 10 + M[i] // return the better answer return max(prefix_less, prefix_equal) // the main code read(S) read(M) best = 0 for k = 1; k ≤ |M| - |S| + 1; k++: best = max(best, solve(M, S, k)) print(best)
Can be found here.
Can be found here.