Coding Test: Find the Largest Stable Number | 笔试: 寻找最大的稳定数
Problem 题面
Give a number $N$, find the largest number $k$ satisfy the following requirements smaller than $N$:
Sum of all digits of $k$ is prime
Each digits of $k$ is larger than or equals to the previous digit (e.g. 123456, 111111)
给定一个上限$N$, 寻找最大的小于$N$的数字$k$,要求满足以下条件:
$k$的各个数位之和是素数
$k$的每一位都比前一位大 (比如 123455, 11111)
Input 输入
One line with one number $N$
一行,一个数字$N$
Output 输出
One line with one number $k$ satisfy the requirements or $-1$ if there is no solution
一行,一个满足条件的数字$k$,如果没有符合条件的答案输出$-1$
Size and Limits 数据规模和限制
$N \leq 10^{18}$
Time Limits 时间限制: 200ms
Solution 题解
Obviously, the simplest approach is to try each number from $N$ down to $1$; if it satisfies the condition, return it, otherwise return $-1$. However, given the data scale up to $10^{18}$, this approach will definitely time out. By observing that the number of satisfying numbers is much smaller than the total range, we use a reverse thinking: generate numbers that meet the conditions via a search algorithm.
First list all possible primes via the sieve method
首先,通过筛法列出所有可能的素数:
1 2 3 4 5 6 7 8 9 10 11 12
num = int(input().strip())
defprimes(n): sieve = [True] * (n + 1) sieve[0] = sieve[1] = False for i inrange(2, int(math.sqrt(n)) + 1): if sieve[i]: for j inrange(i * i, n + 1, i): sieve[j] = False return [i for i inrange(n + 1) if sieve[i]]
primes_list = primes(len(str(num)) * 9 + 1)
For each prime, find the largest number with non-decreasing digits and digit-sum equal to that prime
ans = -1 for p in primes_list: digits = [0for _ inrange(len(str(num)))] upper_limit = [int(d) for d instr(num)] left = p res = largest_stable_number(0, digits, left, upper_limit) if res != -1: ans = max(ans, res) print(ans)
Implement the DFS function to build the largest valid number
Convert the number to a digit array for easy generation.
If the sum of digits so far exceeds the target prime, prune this branch.
If all digits are assigned and the remaining sum is zero, return the constructed number.
Generate digits from most significant to least significant, iterating from the maximum allowable digit down to the minimum to ensure the first found solution is the largest.
Determine the upper bound for the current digit: if all previous digits match the corresponding digits of $N$, the upper bound is that digit of N; otherwise it is $9$.
Determine the lower bound for the current digit: it must be at least the previous digit to maintain non-decreasing order (or $0$ if it’s the first digit).
For the current position, try all digits in [lower_bound, upper_bound] in descending order; if a recursive call returns a valid number, return it immediately.
deflargest_stable_number(cur: int, digits, left: int, upper_limit) -> int: if left < 0: return -1 if cur == len(digits): if left != 0: return -1 returnint(''.join(map(str, digits))) with_limit = True for i inrange(cur): if digits[i] < upper_limit[i]: with_limit = False break top = upper_limit[cur] if with_limit else9 for i inrange(top, (0if cur == 0else digits[cur - 1])-1, -1): digits[cur] = i res = largest_stable_number(cur + 1, digits, left - i, upper_limit) if res != -1: return res return -1
defprimes(n): sieve = [True] * (n + 1) sieve[0] = sieve[1] = False for i inrange(2, int(math.sqrt(n)) + 1): if sieve[i]: for j inrange(i * i, n + 1, i): sieve[j] = False return [i for i inrange(n + 1) if sieve[i]]
primes_list = primes(len(str(num)) * 9 + 1)
deflargest_stable_number(cur: int, digits, left: int, upper_limit) -> int: if left < 0: return -1 if cur == len(digits): if left != 0: return -1 returnint(''.join(map(str, digits))) with_limit = True for i inrange(cur): if digits[i] < upper_limit[i]: with_limit = False break top = upper_limit[cur] if with_limit else9 for i inrange(top, (0if cur == 0else digits[cur - 1])-1, -1): digits[cur] = i res = largest_stable_number(cur + 1, digits, left - i, upper_limit) if res != -1: return res return -1
ans = -1 for p in primes_list: digits = [0for _ inrange(len(str(num)))] upper_limit = [int(d) for d instr(num)] left = p res = largest_stable_number(0, digits, left, upper_limit) if res != -1: ans = max(ans, res) print(ans)
And for Rust Lovers, here is the Rust version of code: