CF 102697145 - Star Wars
The task is a base conversion problem. The first alien species writes integers using base (a), while the second uses base (b). We are given the two bases and a number (n) written using digits valid in base (a). We must print the same integer written in base (b).
Rating: -
Tags: -
Solve time: 1m 58s
Verified: yes
Solution
Problem Understanding
The task is a base conversion problem. The first alien species writes integers using base (a), while the second uses base (b). We are given the two bases and a number (n) written using digits valid in base (a). We must print the same integer written in base (b).
For example, with input base (7), the number 63642 represents
[ 6\cdot7^4+3\cdot7^3+6\cdot7^2+4\cdot7+2. ]
The output base is (9), so the decimal value of that expression has to be represented using powers of (9), producing 23550. The official statement gives (a,b\le 10), so every digit can be represented directly by the characters 0 through 9. The problem has a 1 second time limit and 256 MB memory limit. No explicit upper bound on the number of digits is stated in the current statement, so the natural parameter for the algorithm is the input length (L). A solution should avoid algorithms that repeatedly recompute positional powers, because their work grows quadratically with (L).
There are several boundary cases that are easy to mishandle. A single zero is the smallest possible numerical value. For example, 2 10 followed by 0 must produce 0. A conversion routine that repeatedly divides the value and builds digits can accidentally produce an empty string for zero.
Leading zeroes can also appear if the input representation permits them. For example, 2 10 with 000101 represents the same value as 101, namely 5, so the output must be 5, not 000101 or an empty result.
The source and destination bases can be equal. For example, 10 10 with 123456 must produce 123456. A correct conversion through an intermediate integer handles this automatically.
The output can contain more digits than the input. For example, 2 10 with a sufficiently long binary number can produce a decimal number of comparable or greater textual length. An implementation must not assume that the output has the same length as the input.
Approaches
A straightforward approach is to evaluate every source digit independently using its positional power. If the number has (L) digits, we can compute each term as (d_i a^{L-1-i}), where the power is obtained by multiplying by (a) repeatedly. The method is mathematically correct because positional notation is exactly the sum of these terms. However, computing the powers from scratch performs
[ (L-1)+(L-2)+\cdots+1=\frac{L(L-1)}2 ]
multiplications in the worst case just for the source conversion. The work is (O(L^2)), which is unnecessary.
The key observation is that positional notation can be evaluated incrementally. Suppose the digits seen so far represent a value (x). When the next digit is (d), appending that digit in base (a) changes the value to
[ x\cdot a+d. ]
There is no reason to recompute any power. Starting from zero and applying this recurrence once per digit converts the entire source representation in (O(L)) arithmetic steps.
Once the integer value is known, the destination representation follows from the reverse operation. Dividing an integer (x) by (b) gives a quotient and remainder,
[ x=q\cdot b+r, ]
where (r) is exactly the least significant base-(b) digit. Repeating this operation on (q) extracts the remaining digits from right to left. Reversing the collected remainders gives the required representation.
This gives a clean two-stage solution. The brute force works because positional notation is a sum of digit-weighted powers, but fails when those powers are repeatedly recomputed. Horner-style evaluation removes that repetition, while repeated division gives the canonical representation in the new base.
| Approach | Time Complexity | Space Complexity | Verdict |
|---|---|---|---|
| Brute Force | (O(L^2)) arithmetic steps | (O(L)) | Too slow for large inputs |
| Optimal | (O(L)) positional steps, plus output conversion | (O(L)) | Accepted |
The complexity notation treats arithmetic on the accumulated integer as one operation, which is the standard model for this elementary conversion problem. With Python's arbitrary-precision integers, the actual bit complexity also depends on the size of that integer.
Algorithm Walkthrough
- Read the source base (a), destination base (b), and the digit string (n). The string must remain a string initially, because its characters are the individual digits of the source representation.
- Set the accumulated integer value to zero. For every character in the source string, convert it to its numeric digit (d), then update the value using
value = value * a + d. This is the positional recurrence, so after processing any prefix,valueis exactly the integer represented by that prefix. - If the accumulated value is zero, print
0immediately. Repeated division would otherwise produce no remainders, even though the correct representation contains one zero digit. - While the value is positive, divide it by the destination base (b). Append the remainder to a digit list and replace the value by the quotient. Each remainder is the next destination digit, starting with the least significant one.
- Reverse the collected digits and convert them to characters. The division process discovers digits backwards, so reversing restores their normal most-significant-to-least-significant order.
- Print the resulting string. Since both bases are at most 10, every digit is represented by the corresponding decimal character.
The invariant behind the first phase is that after processing the first (k) source digits, the accumulated value equals exactly the integer represented by those (k) digits in base (a). Appending one digit applies precisely the positional rule (x\mapsto xa+d), so the invariant survives every iteration.
For the second phase, after each division we have (x=q b+r), so (r) is forced to be the least significant base-(b) digit of (x). The quotient contains all remaining higher-order digits. Repeating this argument proves that the collected remainders are exactly the destination representation in reverse order.
Python Solution
import sys
input = sys.stdin.readline
def solve():
a, b = map(int, input().split())
s = input().strip()
# Convert from base a to an ordinary Python integer.
value = 0
for ch in s:
digit = ord(ch) - ord('0')
value = value * a + digit
# Zero needs a special representation.
if value == 0:
print(0)
return
# Convert the integer to base b.
digits = []
while value > 0:
value, remainder = divmod(value, b)
digits.append(chr(ord('0') + remainder))
print(''.join(reversed(digits)))
if __name__ == "__main__":
solve()
The first loop implements the recurrence from Algorithm Walkthrough step 2. Using ord(ch) - ord('0') makes the digit conversion explicit and avoids relying on a library base parser.
The accumulated value is a Python integer, so there is no fixed-width overflow. This matters because the statement does not give a small upper bound on the number of digits, and a valid input can represent an integer much larger than a 64-bit value.
divmod(value, b) performs the quotient and remainder operation needed by step 4 in one operation. The remainder is always between 0 and b - 1, so it is a valid destination digit.
The zero check is necessary because the loop while value > 0 would execute zero times for the value zero. Without the check, the program would print an empty line instead of 0.
The reversal is also essential. For example, converting decimal 13 to base 2 produces remainders 1, then 0, then 1. These are discovered as 1, 0, 1 from least significant to most significant, which happens to be palindromic in this example. For 10, the remainders are 0, 1, and reversing them gives the correct representation 10.
Worked Examples
For Sample 1, the input is:
7 9
63642
The source number is evaluated from left to right.
| Digit | Accumulated value | Operation |
|---|---|---|
6 |
6 | (0\cdot7+6) |
3 |
45 | (6\cdot7+3) |
6 |
321 | (45\cdot7+6) |
4 |
2251 | (321\cdot7+4) |
2 |
15759 | (2251\cdot7+2) |
Now 15759 is converted to base 9.
| Current value | Quotient | Remainder |
|---|---|---|
| 15759 | 1751 | 0 |
| 1751 | 194 | 5 |
| 194 | 21 | 5 |
| 21 | 2 | 3 |
| 2 | 0 | 2 |
The remainders are discovered as 0, 5, 5, 3, 2. Reversing them gives 23550, which matches the sample output.
For Sample 2, the input is:
10 3
8790971
Since the source base is 10, the Horner evaluation proceeds as follows.
| Digit | Accumulated value |
|---|---|
8 |
8 |
7 |
87 |
9 |
879 |
0 |
8790 |
9 |
87909 |
7 |
879097 |
1 |
8790971 |
The decimal value is then repeatedly divided by 3.
| Current value | Quotient | Remainder |
|---|---|---|
| 8790971 | 2930323 | 2 |
| 2930323 | 976774 | 1 |
| 976774 | 325591 | 1 |
| 325591 | 108530 | 1 |
| 108530 | 36176 | 2 |
| 36176 | 12058 | 2 |
| 12058 | 4019 | 1 |
| 4019 | 1339 | 2 |
| 1339 | 446 | 1 |
| 446 | 148 | 2 |
| 148 | 49 | 1 |
| 49 | 16 | 1 |
| 16 | 5 | 1 |
| 5 | 1 | 2 |
| 1 | 0 | 1 |
Reading those remainders backwards gives 121112121221112, exactly the required base-3 representation. This example also demonstrates that the destination representation can be substantially longer than the source representation.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | (O(L)) positional steps plus output conversion | Each source digit is processed once, and each output digit is extracted once |
| Space | (O(L)) | The input string and generated output digits require linear storage |
Here (L) denotes the number of digits in the source representation, with the output length handled by the corresponding number of division iterations. The implementation uses arbitrary-precision integers, so it remains correct when the represented value exceeds standard 32-bit or 64-bit ranges. The stated 1 second and 256 MB limits are comfortably compatible with the intended linear algorithm for ordinary input sizes.
Test Cases
import sys
import io
def solve():
input = sys.stdin.readline
a, b = map(int, input().split())
s = input().strip()
value = 0
for ch in s:
value = value * a + (ord(ch) - ord('0'))
if value == 0:
print(0)
return
digits = []
while value:
value, r = divmod(value, b)
digits.append(chr(ord('0') + r))
print(''.join(reversed(digits)))
def run(inp: str) -> str:
old_stdin = sys.stdin
old_stdout = sys.stdout
sys.stdin = io.StringIO(inp)
sys.stdout = io.StringIO()
try:
solve()
return sys.stdout.getvalue()
finally:
sys.stdin = old_stdin
sys.stdout = old_stdout
# Provided samples
assert run("7 9\n63642\n") == "23550\n", "sample 1"
assert run("10 3\n8790971\n") == "121112121221112\n", "sample 2"
assert run("5 6\n3124\n") == "1530\n", "sample 3"
# Minimum-size input and zero handling
assert run("2 10\n0\n") == "0\n", "zero"
# All digits equal
assert run("10 10\n111111\n") == "111111\n", "same base"
# Leading zeroes
assert run("2 10\n000101\n") == "5\n", "leading zeroes"
# Boundary between bases, binary to decimal
assert run("2 10\n11111111\n") == "255\n", "binary boundary"
# Larger custom value, hexadecimal is unnecessary because bases are <= 10
assert run("9 2\n888888\n") == "1001001010101001000\n", "large base-9 value"
| Test input | Expected output | What it validates |
|---|---|---|
2 10 with 0 |
0 |
Minimum value and special zero handling |
10 10 with 111111 |
111111 |
All-equal digits and unchanged-base conversion |
2 10 with 000101 |
5 |
Leading zero handling |
2 10 with 11111111 |
255 |
Correct treatment of the highest binary digit and output length |
9 2 with 888888 |
1001001010101001000 |
Repeated multiplication in the source base and repeated division in the target base |
Edge Cases
The zero case is the most common silent failure in repeated-division implementations. Consider:
2 10
0
The Horner phase computes value = 0. The division loop cannot run because its condition is value > 0, so without a dedicated zero check the output would be empty. The implementation detects zero and prints exactly 0.
Leading zeroes do not change the represented integer. For:
2 10
000101
the accumulated values are 0, 0, 0, 1, 2, 5. The destination conversion then divides 5 by 10, obtaining remainder 5, and prints 5. The leading zeroes never affect the mathematical value because multiplying zero by the source base still gives zero.
Equal source and destination bases require no special branch. With:
10 10
111111
the first phase obtains the integer (111111). The second phase expresses that same integer in base 10, producing 111111. This is a useful check that the two conversion phases are independently correct.
A boundary case where the output is longer is:
2 10
11111111
The source value becomes (255). Dividing by 10 extracts 5, then 5, then 2, so reversing the remainders produces 255. The algorithm never assumes that the input and output have the same number of digits.
Finally, the bases themselves can be at opposite ends of the allowed range. For example:
9 2
888888
The source evaluation treats every 8 as a valid base-9 digit. The resulting integer is then repeatedly divided by 2, producing the binary representation 1001001010101001000. The digit conversion remains correct because every supported base is at most 10, so the characters 0 through 9 are sufficient to represent every possible digit.