Codeforces Round #EDR118 Editorial

A - Long Comparison

To compare two numbers represented as x1 * 10^p1 and x2 * 10^p2, first compare their total digit lengths: len(x1) + p1 vs len(x2) + p2. If unequal, the result is immediate. Otherwise, reduce both exponents by their minimum to ensure at least one becomes zero. Then scale the base integers accordingly and compare directly. Since the scaled values remain under 1e6, standard integer types suffice.

Given an array, select n/2 pairs such that all remainders modulo the smaller element are absent from the original array. Sorting the array allows pairing the smallest element with any other n/2 elements—since all remainders will be less than the smallest value, they cannot appear in the array.

Use binary search on the damage per hit k. For a candidate k, simulate the total damage over attack times: between consecutive attacks, the damage is capped by the time gap. The total must be at least H. Binary search over [1, H] yields the minimal valid k.

void solve() { int n = read(); long long H = read(); vector t(n); for (long long &x : t) x = read(); long long lo = 1, hi = H; while (lo < hi) { long long mid = (lo + hi) / 2; if (valid(mid, t, H)) hi = mid; else lo = mid + 1; } cout << lo << '\n'; }


</details>### D - MEX Sequences

A sequence is MEX-correct if every prefix has MEX equal to its last element or one more. Valid sequences consist of an initial non-decreasing segment where each new element is either equal to, one more than, or two more than the current MEX, followed by arbitrary repetitions of the final value and `MEX+2`.

We use dynamic programming: `dp[x]` tracks the number of valid prefixes ending with value `x`. As we process each element `a[i]`, we update `dp[a[i]]` using transitions from `dp[a[i]-1]` (for extending the chain) and accumulate contrbiutions where `a[i]` starts the "tail" segment involving `x` and `x+2`. Fast exopnentiation handles combinations of remaining occurrences.

<details><summary>code</summary>```
const int MOD = 998244353;

long long modpow(long long a, long long b) {
    long long r = 1;
    while (b) {
        if (b & 1) r = r * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return r;
}

void solve() {
    int n = read();
    vector<int> a(n);
    vector<vector<int>> pos(n + 2);
    for (int i = 0; i < n; ++i) {
        a[i] = read();
        pos[a[i]].push_back(i);
    }

    vector<long long> dp(n + 2, 0);
    long long ans = 0;

    auto count_after = [&](int val, int idx) {
        auto &v = pos[val];
        return v.end() - upper_bound(v.begin(), v.end(), idx);
    };

    for (int i = 0; i < n; ++i) {
        int x = a[i];
        // Extend main chain
        if (x == 0)
            dp[0] = (dp[0] + 1) % MOD;
        else
            dp[x] = (dp[x] + dp[x - 1]) % MOD;

        // Start tail segment at position i
        long long base = (x == 0) ? 0 :
                         (x == 1) ? 1 : dp[x - 2];
        if (base == 0) continue;

        long long cnt_x = count_after(x, i);
        long long cnt_x2 = (x >= 2) ? count_after(x - 2, i) : 0;
        long long ways = modpow(2, cnt_x + cnt_x2);
        ans = (ans + base * ways) % MOD;
    }

    for (long long v : dp) ans = (ans + v) % MOD;
    cout << ans << '\n';
}

The robot moves deterministically from '+' cells toward 'L'. A cell can be marked '+' only if it has exactly one unvisited neighbor that leads to 'L' (or is 'L' itself). This induces a reverse BFS from 'L': a cell becomes safe ('+') if it has at most one non-obstacle, unmarked neighbor and at least one marked neighbor. Use a queue to propagate safety outward from 'L', updating neighbor eligibility iterative.

int sx = -1, sy = -1;
for (int i = 0; i < n; ++i)
    for (int j = 0; j < m; ++j)
        if (grid[i][j] == 'L') sx = i, sy = j;

vector<vector<bool>> safe(n, vector<bool>(m, false));
queue<pair<int, int>> q;
q.emplace(sx, sy);
safe[sx][sy] = true;

const int dx[4] = {0, 1, 0, -1};
const int dy[4] = {-1, 0, 1, 0};

auto can_mark = [&](int x, int y) {
    if (x < 0 || x >= n || y < 0 || y >= m) return false;
    if (safe[x][y] || grid[x][y] == '#') return false;
    int safe_neighbors = 0, free_neighbors = 0;
    for (int d = 0; d < 4; ++d) {
        int nx = x + dx[d], ny = y + dy[d];
        if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
        if (safe[nx][ny]) ++safe_neighbors;
        else if (grid[nx][ny] != '#') ++free_neighbors;
    }
    return safe_neighbors > 0 && free_neighbors <= 1;
};

while (!q.empty()) {
    auto [x, y] = q.front(); q.pop();
    for (int d = 0; d < 4; ++d) {
        int nx = x + dx[d], ny = y + dy[d];
        if (can_mark(nx, ny)) {
            safe[nx][ny] = true;
            q.emplace(nx, ny);
        }
    }
}

for (int i = 0; i < n; ++i) {
    for (int j = 0; j < m; ++j) {
        if (safe[i][j] && grid[i][j] != 'L')
            cout << '+';
        else
            cout << grid[i][j];
    }
    cout << '\n';
}

}


</details>### F - Tree Coloring

Omitted due to external reference.

Tags: Codeforces competitive-programming algorithms

Posted on Wed, 07 Oct 2026 16:44:20 +0000 by omniuni