For a given number $x$, we can check whether it is valid or not (i.e. whether chain rounding gives a different result than directly rounding) by directly simulating the chain rounding process. This can be done in $\mathcal{O}(\log N)$ time.
//round u to the nearest d int round (int u, int d) { if (u % d < d/2) { return u - u % d; } return u + d - u % d; } //chain round u to the nearest target int chain_round(int u, int target){ for(int ten = 10; ten<=target; ten *= 10){ u = round(u, ten); } return u; }
For the $N \leq 1000$ subtask, we can check each $x$ from $2$ to $N$ using brute force. We will loop over each number and check if it chain rounds to a different number than directly rounding. The total complexity is $\mathcal{O}(N \log N)$ per test case.
For the $N \leq 10^6$ subtask, we note that if there are $V$ valid $x$ from $2$ to $N-1$, there are either $V$ or $V+1$ valid numbers from $2$ to $N$, depending on whether $N$ itself is valid. This motivates us to precompute for each $N$ the number of valid $x$ before processing any of the test cases and storing it into an array. This lowers our time complexity to $\mathcal{O}(1)$ per test case! We still need $\mathcal{O}(N \log N)$ time to precompute all possible answers, so our final time complexity is $\mathcal{O}(N \log N + T)$ where $T$ is the number of test cases.
#include <iostream> #include <vector> // round u to the nearest d int round (int u, int d) { if (u % d < d/2) { return u - u % d; } return u + d - u % d; } //chain round u to the nearest target int chain_round(int u, int target){ for(int ten = 10; ten<=target; ten *= 10){ u = round(u, ten); } return u; } int main () { const int maxN = 1'000'000; std::vector<int> ans(maxN+1); ans[1] = 0; for(int N = 2; N <= maxN; N++){ int V = ans[N-1]; int target = 1; while(target < N){ target *= 10; } if(chain_round(N, target) != round(N, target)){ V++; } ans[N] = V; } int T; std::cin >> T; while (T--) { int N; std::cin >> N; std::cout << ans[N] << "\n"; } }
For $N \leq 10^9$, it is now too slow to check for each $x$ whether or not it is valid, so we have to make some observations about chain rounding.
With some experimentation, we can observe that all valid $x$ have a prefix of at least one $4$ (prefix starting from the left), and the first digit not equal to a $4$ must be $5$, $6$, $7$, $8$, or $9$.
For instance, $4451$, $450$, and $45$ will be valid but $4$, $50$, and $7455$ are not.
If we fix the length of $x$ to be $L$, then $x$ must be in the range $[\overbrace{44\dots 4}^{L-1}5, 4\overbrace{99\dots 9}^{L-1}]$. We can loop over all possible $L$ (as $N \leq 10^{9}$, the maximum $L$ is at most $9$) and check for each one, how many valid $x$ of length $L$ are less than or equal to $N$.
Complexity $\mathcal{O}(\log N)$ per test case.
Anand John's Python code follows. Note that the time complexity is worse than $\mathcal{O}(\log N)$ due to conversions from strings to integers, but it is still fast enough to pass.
def alg(N): digits = 0 while 10**digits < N: digits += 1 answer = 0 for curdigits in range(1, digits+1): upper = int('5'+'0'*(curdigits-1))-1 upper = min(N, upper) lower = int('4'*curdigits) answer += max(0, upper - lower) return answer T = int(input().strip()) for _ in range(T): N = int(input().strip()) print(alg(N))
Brandon Wang's C++ code:
#include <iostream> #include <vector> //determines the length of the intersection of [a, b] with [c, d] int isect(int a, int b, int c, int d) { int lb = std::max(a, c); int ub = std::min(b, d); return std::max(0, ub - lb + 1); } int solve(int n) { int is = 5, ie = 49; int tp = 1; int ans = 0; while (tp < 100000000) { tp *= 10; is += 4 * tp; ie = 5 * tp - 1; ans += isect(is, ie, 2, n); } return ans; } int main() { int T; std::cin >> T; while (T--) { int n; std::cin >> n; std::cout << solve(n) << "\n"; } }