Algorithmic Problem Solutions with Data Structures

Fountain Construction Optimization

Three construction strategies exist: using only coins, only diamonds, or a combination. Iterate through coin-based fountains while tracking maximum aesthetic value achievable with remaining coins via a segment tree. Similarly process diamond-based options and update combined solutions during iteration.

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
using ll = long long;

template<typename T>
class SegmentTree {
public:
    struct Node { ll L, R, MaxVal; };
    vector<Node> tree;
    int size;

    SegmentTree(int n) : size(n) {
        tree.resize(n * 4);
        build(1, 1, n);
    }

    void build(int idx, int left, int right) {
        tree[idx] = {left, right, 0};
        if (left == right) return;
        int mid = (left + right) / 2;
        build(idx*2, left, mid);
        build(idx*2+1, mid+1, right);
    }

    void update(int idx, int pos, ll value) {
        if (tree[idx].L == tree[idx].R) {
            tree[idx].MaxVal = max(tree[idx].MaxVal, value);
            return;
        }
        int mid = (tree[idx].L + tree[idx].R) / 2;
        if (pos <= mid) update(idx*2, pos, value);
        else update(idx*2+1, pos, value);
        tree[idx].MaxVal = max(tree[idx*2].MaxVal, tree[idx*2+1].MaxVal);
    }

    ll query(int idx, int ql, int qr) {
        if (ql <= tree[idx].L && tree[idx].R <= qr) 
            return tree[idx].MaxVal;
        int mid = (tree[idx].L + tree[idx].R) / 2;
        if (qr <= mid) return query(idx*2, ql, qr);
        if (ql > mid) return query(idx*2+1, ql, qr);
        return max(query(idx*2, ql, qr), query(idx*2+1, ql, qr));
    }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n, coinMax, diamondMax;
    cin >> n >> coinMax >> diamondMax;
    
    vector<vector<pair<int, int>>> materials(2);
    for (int i = 0; i < n; i++) {
        int beauty, price;
        char type;
        cin >> beauty >> price >> type;
        materials[type-'C'].push_back({beauty, price});
    }

    SegmentTree<ll> coinTree(coinMax), diamondTree(diamondMax);
    int result = 0;
    
    for (auto [val, cost] : materials[0]) {
        if (coinMax >= cost) {
            ll remaining = coinMax - cost;
            ll best = (remaining > 0) ? coinTree.query(1, 1, remaining) : 0;
            if (best) result = max(result, val + (int)best);
        }
        coinTree.update(1, cost, val);
    }

    ll coinBest = (coinMax > 0) ? coinTree.query(1, 1, coinMax) : 0;
    for (auto [val, cost] : materials[1]) {
        if (diamondMax >= cost) {
            ll remaining = diamondMax - cost;
            ll best = (remaining > 0) ? diamondTree.query(1, 1, remaining) : 0;
            if (best || coinBest) 
                result = max(result, val + (int)max(best, coinBest));
        }
        diamondTree.update(1, cost, val);
    }

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

Same Differences Counting

Transform the condition a_j - a_i = j - i into a_i - i = a_j - j. Maintain frequency counts of a_i - i values during iteration to efficiently compute valid pairs.

#include <iostream>
#include <map>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int testCases;
    cin >> testCases;
    while (testCases--) {
        int n;
        cin >> n;
        map<int, long long> freq;
        long long total = 0;
        
        for (int idx = 1; idx <= n; idx++) {
            int num;
            cin >> num;
            total += freq[num - idx];
            freq[num - idx]++;
        }
        cout << total << '\n';
    }
    return 0;
}

Lexicographical Order Validation

Establish character precedence relationships from adjacent string comparisons. Perform topological sorting to determine valid alphabet ordering, detecting cycles for invalid cases.

#include <iostream>
#include <vector>
#include <queue>
#include <set>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n;
    cin >> n;
    vector<string> words(n);
    for (auto &w : words) cin >> w;
    
    vector<vector<int>> graph(26);
    vector<int> inDegree(26, 0);
    set<string> prefixes;
    
    for (auto &w : words) {
        if (prefixes.count(w)) {
            cout << "Impossible\n";
            return 0;
        }
        for (int len = 1; len <= w.size(); len++) 
            prefixes.insert(w.substr(0, len));
    }

    for (int i = 0; i < n-1; i++) {
        for (int pos = 0; pos < words[i].size(); pos++) {
            if (pos >= words[i+1].size()) {
                cout << "Impossible\n";
                return 0;
            }
            if (words[i][pos] != words[i+1][pos]) {
                int from = words[i][pos] - 'a';
                int to = words[i+1][pos] - 'a';
                graph[from].push_back(to);
                inDegree[to]++;
                break;
            }
        }
    }

    queue<int> process;
    vector<int> sorted;
    for (int i = 0; i < 26; i++) 
        if (!inDegree[i]) process.push(i);
    
    while (!process.empty()) {
        int cur = process.front();
        process.pop();
        sorted.push_back(cur);
        for (int neighbor : graph[cur]) {
            if (--inDegree[neighbor] == 0) 
                process.push(neighbor);
        }
    }

    if (sorted.size() != 26) cout << "Impossible\n";
    else {
        for (int c : sorted) cout << (char)(c + 'a');
    }
    return 0;
}

Nearest Valid House Search

Iterate through house positions, computing minimum distance from target position to houses meeting cost constraints.

#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int houses, target, maxCost;
    cin >> houses >> target >> maxCost;
    vector<int> costs(houses + 1);
    
    for (int i = 1; i <= houses; i++) 
        cin >> costs[i];
    
    long minDist = houses * 10;
    for (int pos = 1; pos <= houses; pos++) {
        if (costs[pos] && costs[pos] <= maxCost) 
            minDist = min(minDist, abs(pos - target) * 10L);
    }
    cout << minDist << '\n';
    return 0;
}

Array Partition Validation

Discretize array values and count contiguous increasing sequences. Verify if the count of sequences is within the allowed partition limit.

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

void solve() {
    int n, k;
    cin >> n >> k;
    vector<int> arr(n);
    for (int i = 0; i < n; i++) cin >> arr[i];
    
    vector<int> sorted = arr;
    sort(sorted.begin(), sorted.end());
    for (int i = 0; i < n; i++) 
        arr[i] = lower_bound(sorted.begin(), sorted.end(), arr[i]) - sorted.begin();
    
    int segments = 0;
    for (int i = 0; i < n; ) {
        int j = i;
        while (j+1 < n && arr[j+1] == arr[j] + 1) j++;
        segments++;
        i = j + 1;
    }
    cout << (segments <= k ? "Yes" : "No") << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int tests;
    cin >> tests;
    while (tests--) solve();
    return 0;
}

Threshold Achievement Detection

Maintain maximum prefix sums using segment trees to efficiently determine when cumulative values exceed dynamic thresholds.

#include <iostream>
#include <vector>
#include <functional>
#include <iomanip>
using namespace std;
using ll = long long;

struct SegNode { ll L, R, PrefixMax, Total; };

class PrefixSumTree {
    vector<SegNode> data;
    int size;

    void combine(SegNode &parent, SegNode &left, SegNode &right) {
        parent.Total = left.Total + right.Total;
        parent.PrefixMax = max(left.PrefixMax, left.Total + right.PrefixMax);
    }

public:
    PrefixSumTree(vector<int> base) : size(base.size()-1) {
        data.resize(4 * size);
        function<void(int, int, int)> build = [&](int idx, int l, int r) {
            data[idx] = {l, r, 0, 0};
            if (l == r) {
                data[idx] = {l, r, base[l], base[l]};
                return;
            }
            int mid = (l + r) / 2;
            build(idx*2, l, mid);
            build(idx*2+1, mid+1, r);
            combine(data[idx], data[idx*2], data[idx*2+1]);
        };
        build(1, 1, size);
    }

    void modify(int idx, int pos, int value) {
        if (data[idx].L == data[idx].R) {
            data[idx].Total = value;
            data[idx].PrefixMax = value;
            return;
        }
        int mid = (data[idx].L + data[idx].R) / 2;
        if (pos <= mid) modify(idx*2, pos, value);
        else modify(idx*2+1, pos, value);
        combine(data[idx], data[idx*2], data[idx*2+1]);
    }

    SegNode findThreshold(int idx, ll current, ll threshold) {
        if (data[idx].L == data[idx].R) 
            return {0,0, current + data[idx].PrefixMax, 0};
        
        if (current + data[idx*2].PrefixMax >= threshold)
            return findThreshold(idx*2, current, threshold);
        else
            return findThreshold(idx*2+1, current + data[idx*2].Total, threshold);
    }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n, k, queries;
    cin >> n >> k >> queries;
    vector<int> base(n+1);
    for (int i = 1; i <= n; i++) {
        cin >> base[i];
        base[i] -= k;
    }

    PrefixSumTree tree(base);
    while (queries--) {
        int pos, value;
        cin >> pos >> value;
        tree.modify(1, pos, value - k);
        auto res = tree.findThreshold(1, 0, 0);
        double result = k + static_cast<double>(res.PrefixMax) / res.L;
        cout << fixed << setprecision(15) << result << '\n';
    }
    return 0;
}

Digit Separation Scheme

Separate digits into odd and even positions, interpret as distinct numbers, and compute valid combination count.

#include <iostream>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int tests;
    cin >> tests;
    while (tests--) {
        string num;
        cin >> num;
        long odd = 0, even = 0;
        
        for (int i = 0; i < num.size(); i++) {
            if (i % 2 == 0) even = even * 10 + (num[i] - '0');
            else odd = odd * 10 + (num[i] - '0');
        }
        cout << (odd + 1) * (even + 1) - 2 << '\n';
    }
    return 0;
}

Multidimensional Resource Allocation

Implement dynamic programming with multiple constraints to determine minimum cost for achieving multidimensional resource thresholds.

#include <iostream>
#include <cstring>
#include <climits>
using namespace std;

const long long INF = 9e18;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int items, dims, target;
    cin >> items >> dims >> target;
    vector<int> thresholds(5, target);
    long dp[7][7][7][7][7];
    memset(dp, 0x3f, sizeof dp);
    dp[0][0][0][0][0] = 0;
    
    for (int i = 1; i <= items; i++) {
        int cost;
        cin >> cost;
        vector<int> vals(5,0);
        for (int d = 0; d < dims; d++) cin >> vals[d];
        
        for (int d1 = thresholds[0]; d1 >= 0; d1--)
        for (int d2 = thresholds[1]; d2 >= 0; d2--)
        for (int d3 = thresholds[2]; d3 >= 0; d3--)
        for (int d4 = thresholds[3]; d4 >= 0; d4--)
        for (int d5 = thresholds[4]; d5 >= 0; d5--) {
            int nd1 = min(d1 + vals[0], thresholds[0]);
            int nd2 = min(d2 + vals[1], thresholds[1]);
            int nd3 = min(d3 + vals[2], thresholds[2]);
            int nd4 = min(d4 + vals[3], thresholds[3]);
            int nd5 = min(d5 + vals[4], thresholds[4]);
            dp[nd1][nd2][nd3][nd4][nd5] = min(
                dp[nd1][nd2][nd3][nd4][nd5],
                dp[d1][d2][d3][d4][d5] + cost
            );
        }
    }
    
    long result = dp[target][target][target][target][target];
    if (result > INF/2) cout << -1 << '\n';
    else cout << result << '\n';
    return 0;
}

Arithmetic Sequence Validation

Analyze sorted sequence differences to identify removable elements that would restore arithmetic progression properties.

#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
using ll = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n;
    cin >> n;
    if (n < 4) {
        cout << "1\n";
        return 0;
    }

    vector<pair<ll, int>> items(n);
    for (int i = 0; i < n; i++) {
        cin >> items[i].first;
        items[i].second = i+1;
    }
    sort(items.begin(), items.end());

    multiset<ll> intervals;
    for (int i = 2; i < n-1; i++)
        intervals.insert(items[i].first - items[i-1].first);

    ll firstDiff = items[1].first - items[0].first;
    ll lastDiff = items[n-1].first - items[n-2].first;
    
    if (intervals.size() && *intervals.begin() == *intervals.rbegin()) {
        if (firstDiff == *intervals.begin()) {
            cout << items[n-1].second << '\n';
            return 0;
        }
        else if (lastDiff == *intervals.begin()) {
            cout << items[0].second << '\n';
            return 0;
        }
    }

    intervals.insert(firstDiff);
    intervals.insert(lastDiff);
    
    for (int i = 1; i < n-1; i++) {
        ll prevDiff = items[i].first - items[i-1].first;
        ll nextDiff = items[i+1].first - items[i].first;
        ll merged = items[i+1].first - items[i-1].first;
        
        intervals.erase(intervals.find(prevDiff));
        intervals.erase(intervals.find(nextDiff));
        intervals.insert(merged);
        
        if (*intervals.begin() == *intervals.rbegin()) {
            cout << items[i].second << '\n';
            return 0;
        }
        
        intervals.erase(intervals.find(merged));
        intervals.insert(prevDiff);
        intervals.insert(nextDiff);
    }
    cout << "-1\n";
    return 0;
}

Time-Based Path Optimization

Utilize Dijkstra's algorithm with time-event tracking to compute earliest arrival times through temporally constrained paths.

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
using ll = long long;

vector<vector<int>> timeEvents;

class TimeGraph {
    vector<vector<pair<int, int>>> adj;
    vector<ll> arrival;
    int nodes;

public:
    TimeGraph(int n) : nodes(n) {
        adj.resize(n+1);
        arrival.assign(n+1, -1);
    }

    void addEdge(int u, int v, int edgeType) {
        adj[u].push_back({v, edgeType});
        adj[v].push_back({u, edgeType});
    }

    void computePaths(int start) {
        priority_queue<pair<ll, int>, vector<pair<ll, int>>, greater<>> pq;
        pq.push({0, start});
        
        while (!pq.empty()) {
            auto [time, node] = pq.top();
            pq.pop();
            if (arrival[node] != -1) continue;
            arrival[node] = time;
            
            for (auto [neighbor, type] : adj[node]) {
                auto it = lower_bound(timeEvents[type].begin(), timeEvents[type].end(), time);
                if (it != timeEvents[type].end()) 
                    pq.push({*it + 1, neighbor});
            }
        }
    }

    ll getTime(int node) { return arrival[node]; }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int nodes, edgeTypes;
    cin >> nodes >> edgeTypes;
    TimeGraph graph(nodes);
    timeEvents.resize(edgeTypes+1);
    
    for (int type = 1; type <= edgeTypes; type++) {
        int count;
        cin >> count;
        while (count--) {
            int u, v;
            cin >> u >> v;
            graph.addEdge(u, v, type);
        }
    }

    int eventCount;
    cin >> eventCount;
    for (int i = 0; i < eventCount; i++) {
        int type;
        cin >> type;
        timeEvents[type].push_back(i);
    }

    graph.computePaths(1);
    cout << graph.getTime(nodes) << '\n';
    return 0;
}

Triangle Formation Game

Apply game theory analysis to determine winning positions based on transformed state values and XOR properties.

#include <iostream>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int tests;
    cin >> tests;
    while (tests--) {
        int a, b, c;
        cin >> a >> b >> c;
        cout << ((a-1) ^ (b-1) ^ (c-1) ? "Win" : "Lose") << '\n';
    }
    return 0;
}

Mouse Survival Probability

Compute survival probabilities through dynamic programming states representing remaining mice counts and transition probabilities.

#include <iostream>
#include <iomanip>
#include <vector>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int white, black;
    cin >> white >> black;
    vector<vector<double>> dp(white+1, vector<double>(black+1, 0));
    
    for (int w = 1; w <= white; w++) {
        dp[w][0] = 1.0;
        if (black >= 1) 
            dp[w][1] = (double)w / (w+1);
    }

    for (int w = 1; w <= white; w++) {
        for (int b = 2; b <= black; b++) {
            dp[w][b] = (double)w / (w+b);
            double blackDraw = (double)b / (w+b);
            double secondBlack = (double)(b-1) / (w+b-1);
            
            if (b >= 2) {
                double whiteEscape = (double)w / (w+b-2);
                dp[w][b] += blackDraw * secondBlack * whiteEscape * dp[w-1][b-2];
            }
            if (b >= 3) {
                double blackEscape = (double)(b-2) / (w+b-2);
                dp[w][b] += blackDraw * secondBlack * blackEscape * dp[w][b-3];
            }
        }
    }
    cout << fixed << setprecision(10) << dp[white][black] << '\n';
    return 0;
}

Tags: segment-tree frequency-map topological-sort array-traversal discretization

Posted on Thu, 14 May 2026 04:23:42 +0000 by adamwhiles