AtCoder Beginner Contest 457
Introduction
The Polaris.AI Programming Contest 2026 (AtCoder Beginner Contest 457) concluded this past Saturday. After taking a virtual contest, I find the problems very cute and interesting. For problems A, B, C, D, and E, I was comfortable with the ideas and solved the problems fairly quickly. Problems F and G were harder but contain some nice ideas. Here I will share some of my thought processes.
By the way, as part of my journey of learning new programming languages, I write all my code in Kotlin. I am also working on a snippet collection for competitive programming in Kotlin as I go.
A. Array
Problem. Given an array of length and integer , find .
Analysis. Ask a toddler on the street.
B. Arrays
Problem. Given an array consisting of arrays and two integers and , output .
Analysis. Ask a Chinese kindergarten student.
C. Long Sequence
Problem. You are given an array consisting of arrays, an integer array of length , and an integer . If is the array constructed by joining copies of for each in this order, find .
Constraints. , , .
Analysis. Simulating can take over steps, which is not feasible. However, we only need to find a single element, so we can use modular arithmetic to skip over almost all of the copies. Let us first find out which array contains the answer; then, we can figure out where in that array the answer lies using the remainder. For some , define
as the number of elements remaining after skipping over . There must exist a unique such that
so the answer will be an element of . To find which one it is, we can take , and is our answer.
D. Raise Minimum
Problem. You are given an array of length and an integer . In one operation, you can choose some and set . After at most operations, what is the maximum possible value of ?
Constraints. , , .
Analysis. This problem immediately reminded me of the example problem about maximum median from the binary search section on USACO Guide. The core idea in that problem was to binary search on the answer, and then count how many operations we need. The same technique applies to this problem. Suppose we fix some . Then, for each , we need
operations to raise to at least (which should hold for all ). Therefore, the minimum number of operations needed is , and the answer is at least if and only if this sum is at most .
Increasing the minimum can only require more operations, so this subproblem is monotonic in . Hence, we binary search on to find the answer.
My code:
val n = nextInt()
val k = nextLong()
val a = LongArray(n) { nextLong() }
var lo = 0L
var hi = Long.MAX_VALUE - 1
while (lo < hi) {
// thanks 15-122
val mid = lo + (hi - lo + 1) / 2
var cost = 0L
for (i in 0 until n) {
val diff = mid - a[i]
if (diff <= 0) continue
cost += (diff + i) / (i + 1)
if (cost > k) break
}
if (cost > k) hi = mid - 1
else lo = mid
}
println(lo)E. Crossing Table Cloth
Problem. You are given segments on the cells . For each of the queries, given integers , determine whether or not there exist exactly two segments such that their union is exactly .
Constraints. , , .
Analysis. I immediately noticed that for the answer to be βYes,β one of the two segments must have an endpoint at and extends rightwards, and one of the two segments must have an endpoint at and extends leftwards. To maximize the coverage greedily, we should make the former extend as much to the right as possible and make the latter extend as much to the left as possible. This motivates us to maintain a list of segments for each start index and each end index. Then, by sorting each of the lists, we can use binary search to efficiently compute the rightmost-extending segment that starts at and ends before , and the leftmost-extending segment that starts after and ends at .
There is one edge case where the two aforementioned greedily chosen segments are the same one. In that case, it must be that the segment is already exactly . Hence, it suffices to check if there exists another segment lying completely inside . This is the same as checking whether there are at least two different segments in .
I recalled that this subproblem can be solved using a Fenwick Tree: sort the queries by descending order in , and maintain a Fenwick Tree on the values of .
This problem overall feels very, very natural, as the steps come out one at a time very logically, and the problem reduces to solving a few well-known subproblems one by one using standard techniques, while still having a fun and quick observation.
My code (note that my Fenwick Tree operates on half-open intervals ):
val n = nextInt()
val m = nextInt()
val start = Array(n + 1) { mutableListOf<Pair<Int, Int>>() }
val end = Array(n + 1) { mutableListOf<Pair<Int, Int>>() }
val intervals = Array(m) {
val l = nextInt()
val r = nextInt()
start[l].add(Pair(r, it))
end[r].add(Pair(l, it))
Pair(l, r)
}
// Sort the start and end arrays
for (i in 1..n) {
start[i].sortWith { x, y ->
if (x.first == y.first) x.second.compareTo(y.second)
else x.first.compareTo(y.first)
}
end[i].sortWith { x, y ->
if (x.first == y.first) x.second.compareTo(y.second)
else x.first.compareTo(y.first)
}
}
val fw = FenwickTree(n + 1)
val q = nextInt()
// Sort the queries by descending order in S
val queries = Array(q) { Triple(nextInt(), nextInt(), it) }
.sortedByDescending { it.first }
intervals.sortByDescending { it.first }
// Maintain a pointer to update the Fenwick Tree using two-pointer
var pt = 0
val ans = BooleanArray(q)
for (query in queries) {
val (s, t, j) = query
// Add the remaining segments that start after S
while (pt < m && intervals[pt].first >= s)
fw.update(intervals[pt++].second, 1)
var a = start[s].binarySearch { if (it.first > t) 1 else -1 }
if (a < 0) a = -a - 1
a--
var b = end[t].binarySearch { if (it.first >= s) 1 else -1 }
if (b < 0) b = -b - 1
if (a < 0 || b >= end[t].size)
ans[j] = false
else if (start[s][a].second == end[t][b].second)
ans[j] = fw.query(t + 1) >= 2L
else
ans[j] = start[s][a].first + 1 >= end[t][b].first
}
for (j in 0 until q)
println(if (ans[j]) "Yes" else "No")F. Second Gap
Problem. Given an integer array of length , count the number of permutations of through , modulo , such that for each , if and are the largest and second-largest values among , then .
Constraints. , .
Analysis. For these types of counting problems, the idea is almost always to use some sort of DP. Furthermore, since the problem is about suffixes, it reminded me that I should consider solving backwards.
I first came up with a naive solution. Let denote the number of possible suffixes that start from and has a maximum at index .
Fix some . Now we can case on whether the largest element or the second-largest element in a suffix appears at position .
If neither is true, then the rest of the suffix only contributes a nonzero count from this transition if and only if . Hence, if , then there are choices for the elements, so for all . If , then set for all .
If the largest element is at position , then the second-largest element (which is previously the largest element) must be at position , so .
If the second-largest element is at position , then the largest element (which is also previously the largest element) must be at position , so .
This is correct but runs in , which is not good. The observation is that most of the updates are βglobalβ (i.e. similar for all the elements). We notice that the transitions are just range multiplication updates and point addition updates, which reminds us of a Lazy Segment Tree. Hence the problem can be solved in time, which is fast enough.
My code (note that my Segment Tree operates on half-open intervals ):
val n = nextInt()
val d = IntArray(n - 1) { nextInt() }
val dp = LazySegmentTree(
n = n + 1,
e = ModLong(0L),
id = ModLong(1L),
defaultValue = ModLong(0L),
op = { a, b -> a + b },
mapping = { f, x -> f * x },
composition = { f, g -> f * g }
)
dp.set(n - 1, ModLong(1L))
dp.set(n, ModLong(1L))
for (i in n - 2 downTo 1) {
val k = i + d[i - 1]
val prev = dp.get(k)
if (d[i] == d[i - 1])
dp.apply(0, n + 1, ModLong((n - i - 1).toLong()))
else
dp.apply(0, n + 1, ModLong(0L))
dp.set(i, dp.get(i) + prev)
dp.set(k, dp.get(k) + prev)
}
val ans = dp.query(0, n + 1)
println(ans)Remark. This problem can also be solved in , by applying a similar lazy idea and using some modular arithmetic tricks. However, the implementation is uglier. See my submission.
G. Catch All Apples
Problem. apples fall on a number line. Apple reaches coordinate at time and must be collected exactly at time . Find the minimum number of robots you need to place so that if the robots have a speed of at most at each moment, there is a way for the robots to collect all apples.
Constraints. , , .
Analysis. This is the most fun problem in this set in my opinion. The task feels very βrealisticβ and natural.
First, I rephrased the problem as follows: what is the minimum number of partitions of the apples we need, such that within each partition, if we sort the apples by increasing , then holds for all .
Now, we can apply the sum-difference substitution trick, which states that if , then
This can be proven with some simple algebra manipulations. Now suppose and . Then by above, if , then .
Now define the partial relation on a pair by if . We can check that is reflexive, symmetric, and transitive, so it is an equivalence relation. Hence the pairs from the apples form a finite partially ordered set, also known as a poset. The problem now reduces to computing the minimum number of chains needed to cover this poset!
We need to recall some Set Theory. By Dilworthβs theorem, the minimum number of chains needed to cover a poset is equal to the maximum length of an antichain. Hence, it suffices to compute the maximum length of an antichain in the pairs .
Note that by definition, are incomparable if and only if or . If we sort them by , then if , items and are incomparable if and only if . The problems further reduces to the following: given an array , what is the longest subsequence of such that for all ?
This is exactly the Longest Decreasing Subsequence (LDS) problem! The solution to this is well-known. For example, we can use dynamic programming with binary search optimization.
To summarize, we transform the apples into pairs where and . After sorting the pairs by in increasing order, the answer is the longest decreasing subsequence in by Dilworthβs theorem.
Since the LIS/LDS problem can be solved in , and the preprocessing is bottlenecked by sorting, the full solution to this problem runs in , which is fast enough.
My code (here I sorted by and ran LDS on , but the same idea works):
val n = nextInt()
// Substitution and sort in the first coordinate
val a = Array(n) {
val t = nextInt()
val x = nextInt()
Pair(t + x, t - x)
}.sortedWith { a, b ->
if (a.first == b.first)
a.second.compareTo(b.second)
else
a.first.compareTo(b.first)
}
// Compute LDS in the second coordinate
val dp = Array(n + 1) { Int.MIN_VALUE }
dp[0] = Int.MAX_VALUE
var ans = 0
for (i in 0 until n) {
val v = a[i].second
var lo = 0
var hi = ans + 1
while (hi - lo > 1) {
val mid = lo + (hi - lo) / 2
if (dp[mid] <= v)
hi = mid
else
lo = mid
}
dp[hi] = v
if (hi > ans) ans = hi
}
println(ans)