Shortest Path with Direction Switching, XOR Subsequence Enumeration, Majority Element Intervals, and Digit-wise Knapsack

A. Grid Navigation with Direction Toggle

Given an n × m grid, start at (1,1) with orientation o = 0. When o = 0, movement is only vertical; when o = 1, only horiznotal. Each move costs 1. At k specified positions, you may flip o (cost 1). Find the minimal cost to reach (n,m).

Solution: Model each toggle point as two nodes—one for each orientation—and connect them with toggle edges. Within rows/columns, connect adjacent points with movement edges weighted by Manhattan distance. Run Dijkstra from the start node (orientation 0 at (1,1)).

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MAXK = 200010;

int read() {
    int x = 0, w = 1; char ch = getchar();
    while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); }
    while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
    return x * w;
}

vector<pair<int, int>> rowPoints[MAXK], colPoints[MAXK];
vector<pair<int, int>> graph[MAXK * 2];

void addEdge(int u, int v, int w) {
    graph[u].emplace_back(v, w);
}

ll dist[MAXK * 2];
bool visited[MAXK * 2];

void dijkstra(int start) {
    fill(dist, dist + MAXK * 2, LLONG_MAX);
    priority_queue<pair<ll, int>, vector<pair<ll, int>>, greater<>> pq;
    dist[start] = 0;
    pq.emplace(0, start);
    while (!pq.empty()) {
        auto [d, u] = pq.top(); pq.pop();
        if (visited[u]) continue;
        visited[u] = true;
        for (auto [v, w] : graph[u]) {
            if (dist[v] > d + w) {
                dist[v] = d + w;
                pq.emplace(dist[v], v);
            }
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n = read(), m = read(), k_input = read();
    vector<int> xs = {1}, ys = {1};
    int k = 1;
    for (int i = 0; i < k_input; ++i) {
        int x = read(), y = read();
        if (x == 1 && y == 1) {
            addEdge(1, 2, 1);
        } else if (x != n || y != m) {
            xs.push_back(x);
            ys.push_back(y);
            ++k;
        }
    }
    xs.push_back(n);
    ys.push_back(m);
    ++k;

    for (int i = 0; i < k; ++i) {
        rowPoints[xs[i]].emplace_back(ys[i], i);
        colPoints[ys[i]].emplace_back(xs[i], i);
    }

    for (int r = 1; r <= n; ++r) {
        sort(rowPoints[r].begin(), rowPoints[r].end());
        for (size_t j = 0; j + 1 < rowPoints[r].size(); ++j) {
            auto [y1, idx1] = rowPoints[r][j];
            auto [y2, idx2] = rowPoints[r][j + 1];
            int diff = y2 - y1;
            int u0 = idx1 * 2 + 1, v0 = idx2 * 2 + 1;
            int u1 = idx1 * 2 + 2, v1 = idx2 * 2 + 2;
            addEdge(u0, v0, diff);
            addEdge(v0, u0, diff);
            addEdge(u0, v1, diff + 1);
            addEdge(v0, u1, diff + 1);
        }
    }

    for (int c = 1; c <= m; ++c) {
        sort(colPoints[c].begin(), colPoints[c].end());
        for (size_t j = 0; j + 1 < colPoints[c].size(); ++j) {
            auto [x1, idx1] = colPoints[c][j];
            auto [x2, idx2] = colPoints[c][j + 1];
            int diff = x2 - x1;
            int u0 = idx1 * 2 + 1, v0 = idx2 * 2 + 1;
            int u1 = idx1 * 2 + 2, v1 = idx2 * 2 + 2;
            addEdge(u1, v1, diff);
            addEdge(v1, u1, diff);
            addEdge(u1, v0, diff + 1);
            addEdge(v1, u0, diff + 1);
        }
    }

    dijkstra(1);
    ll answer = min(dist[k * 2 - 1], dist[k * 2]);
    if (answer == LLONG_MAX) cout << "-1\n";
    else cout << answer << '\n';
    return 0;
}

B. Enumerating XOR Values of Increasing Subsequences

Given an array a of length n (≤10⁶), with values in [0,5000], output all distinct XOR values obtainable from strictly increasing subsequences.

Observation: All possible XOR results lie in [0, 8192). Use dynamic programming over value domain. For each value v, maintain a list of achievable XORs ending with elements ≤ v. When processing element x, extend existing XORs from lists indexed ≤ x, then update higher indices.

#include <bits/stdc++.h>
using namespace std;
const int MAXV = 8192;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n; cin >> n;
    vector<vector<int>> buckets(MAXV);
    vector<int> maxIndex(MAXV, MAXV - 1);
    vector<bool> possible(MAXV, false);
    possible[0] = true;
    int count = 1;

    for (int i = 1; i < MAXV; ++i)
        buckets[i].push_back(0);

    for (int i = 0; i < n; ++i) {
        int x; cin >> x;
        for (int base : buckets[x]) {
            int newVal = base ^ x;
            if (!possible[newVal]) {
                possible[newVal] = true;
                ++count;
            }
            while (maxIndex[newVal] > x) {
                buckets[maxIndex[newVal]--].push_back(newVal);
            }
        }
        buckets[x].clear();
    }

    cout << count << '\n';
    for (int i = 0; i < MAXV; ++i)
        if (possible[i]) cout << i << ' ';
    cout << '\n';
    return 0;
}

C. Counting Intervals with Absolute Majority

Count the number of subarrays where some element appears more than half the time.

O(n√n) approach: Discretize values. For frequent elements (≥√n occurrences), assign +1 to matches and −1 otherwise; count prefix sum inversions via Fenwick tree. For infrequent elements, iterate over all pairs of their positions and compute valid intervals using combinatorial formulas.

O(n log n) approach: For each distinct value w, define Pᵢ = 2·Sᵢ − i, where Sᵢ counts occurrences of w up to i. Valid intervals correspond to Pᵣ > Pₗ. Track segments of constatn slope in P and use three Fenwick trees to maintain coefficients for cubic prefix sums.

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MAXN = 200010;

ll queryFenwick(vector<ll>& bit, int idx) {
    ll res = 0;
    for (; idx > 0; idx -= idx & -idx) res += bit[idx];
    return res;
}

void updateFenwick(vector<ll>& bit, int idx, ll delta, int n) {
    for (; idx <= n; idx += idx & -idx) bit[idx] += delta;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n; cin >> n;
    vector<int> a(n);
    for (int& x : a) cin >> x;

    map<int, vector<int>> positions;
    for (int i = 0; i < n; ++i)
        positions[a[i]].push_back(i + 1);

    ll total = 0;
    const int OFFSET = 200003;

    auto addRange = [&](vector<vector<ll>>& bits, ll l, ll r, ll val) {
        auto apply = [&](int idx, ll coef0, ll coef1, ll coef2) {
            updateFenwick(bits[0], idx, coef0 * val, 2 * OFFSET);
            updateFenwick(bits[1], idx, coef1 * val, 2 * OFFSET);
            updateFenwick(bits[2], idx, coef2 * val, 2 * OFFSET);
        };
        ll t0 = l * l - 3 * l + 2;
        ll t1 = 3 - 2 * l;
        ll t2 = 1;
        apply(l + OFFSET, t0, t1, t2);
        t0 = -(l * l - 3 * l + 2) + (r - l + 1) * (r - l + 2) - 2 * r * (r - l + 1);
        t1 = -(3 - 2 * l) + 2 * (r - l + 1);
        t2 = -1;
        apply(r + 1 + OFFSET, t0, t1, t2);
    };

    auto eval = [&](vector<vector<ll>>& bits, ll x) -> ll {
        ll s0 = queryFenwick(bits[0], x + OFFSET);
        ll s1 = queryFenwick(bits[1], x + OFFSET);
        ll s2 = queryFenwick(bits[2], x + OFFSET);
        return (s0 + s1 * x + s2 * x * x) / 2;
    };

    for (auto& [val, pos] : positions) {
        pos.push_back(n + 1);
        vector<vector<ll>> bits(3, vector<ll>(2 * OFFSET + 10, 0));
        addRange(bits, 0, 0, 1);
        if (pos[0] > 1)
            addRange(bits, -pos[0] + 1, -1, 1);

        ll cnt = 0;
        for (size_t i = 0; i + 1 < pos.size(); ++i) {
            ++cnt;
            ll left = 2 * cnt - pos[i + 1] + 1;
            ll right = 2 * cnt - pos[i];
            total += eval(bits, right - 1) - eval(bits, left - 2);
            addRange(bits, left, right, 1);
        }
    }

    cout << total << '\n';
    return 0;
}

D. Digit-wise Knapsack with Max-per-digit Cost

Given n items (≤20000), each with value ≤10¹², select a subset. The cost is the sum over decimal digits of the maximum digit in that position across selected items. Minimize total cost.

Solution: Process digits from least to most significant. For digit position i (10ⁱ modulus), maintain a set of achievable residues mod 10ⁱ. Prune states: if three residues x < y < z satisfy z − x ≤ 10ⁱ⁻¹, discard y. This ensures ≤10 states per digit, yielding O(n log V) complexity.

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n; cin >> n;
    vector<ll> items(n);
    for (ll& x : items) cin >> x;

    int totalCost = 0;
    ll power = 1;
    for (int digit = 0; digit < 17; ++digit) {
        ll modulus = power * 10;
        vector<ll> states = {0};
        for (ll item : items) {
            vector<ll> newStates;
            for (ll s : states)
                newStates.push_back((s + item) % modulus);
            sort(newStates.begin(), newStates.end());
            states.clear();
            for (ll ns : newStates) {
                if (states.empty() || ns - states.back() >= power)
                    states.push_back(ns);
            }
        }
        totalCost += states.back() / power;
        power = modulus;
    }
    cout << totalCost << '\n';
    return 0;
}

Tags: Dijkstra XOR-subsequence fenwick-tree knapsack-optimization majority-element

Posted on Tue, 20 Oct 2026 16:11:39 +0000 by lhaynes