Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

ACGO Peak Tournament #15: Algorithmic Solutions and Implementation Guide

Tech 1

Problem 1: Tower Ascension

Objective: Identify the first position in a sequence where the value exceeds the initial element.

This problem requires iterating through the input list once. Store the value of the first element as a threshold. During the iteration, compare each subsequent element against this threshold. Upon finding the first match, output the current index (1-based) and terminate. If no such element exists after checking all positions, return -1.

C++ Implementation

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

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    
    int n;
    if (!(cin >> n)) return 0;
    
    vector<int> values(n + 1);
    for (int i = 1; i <= n; ++i) {
        cin >> values[i];
        if (values[i] > values[1]) {
            cout << i << "\n";
            return 0;
        }
    }
    cout << "-1\n";
    return 0;
}

Python Implementation

import sys

def solve():
    try:
        line = sys.stdin.readline()
        if not line:
            return
        n = int(line.strip())
        arr = list(map(int, sys.stdin.readline().split()))
        
        base_val = arr[0]
        for idx in range(1, n):
            if arr[idx] > base_val:
                print(idx + 1)
                return
        print("-1")
    except ValueError:
        pass

if __name__ == "__main__":
    solve()

Problem 2: Nutritional Balance

Objective: Determine if a set of dietary requirements can be fully satisfied given specific food consumption events.

Let (req_k) denote the required amount for nutrient (k). Maintain a running total of deficits. For each food item consumed, reduce the requirement counter for the corresponding nutrients. After processing all items, verify that no nutrient requirement remains positive. Specifically, if any (req_i > 0), the answer is "No"; otherwise, it is "Yes".

C++ Implementation

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

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    
    int days, types;
    if (!(cin >> days >> types)) return 0;
    
    vector<long long> needs(types + 1);
    for (int i = 1; i <= types; ++i) {
        cin >> needs[i];
    }
    
    for (int d = 0; d < days; ++d) {
        for (int t = 1; t <= types; ++t) {
            int val;
            cin >> val;
            needs[t] -= val;
        }
    }
    
    bool possible = true;
    for (int t = 1; t <= types; ++t) {
        if (needs[t] > 0) {
            possible = false;
            break;
        }
    }
    
    cout << (possible ? "Yes" : "No") << "\n";
    return 0;
}

Python Implementation

import sys

def solve():
    input_data = sys.stdin.read().split()
    iterator = iter(input_data)
    
    try:
        n = int(next(iterator))
        m = int(next(iterator))
        
        requirements = []
        for _ in range(m):
            requirements.append(int(next(iterator)))
        
        for _ in range(n):
            for j in range(m):
                val = int(next(iterator))
                requirements[j] -= val
        
        if any(x > 0 for x in requirements):
            print("No")
        else:
            print("Yes")
    except StopIteration:
        pass

if __name__ == "__main__":
    solve()

Problem 3: Sequence Feasibility

Objective: Check if a sequence can be transformed into all positive integers by applying operations based on indices.

Approach A: Greedy Enumeration Sort the array in descending order. Iterate through potential split points. The logic relies on the observation that larger elements are preserved while smaller ones decrease. If at any point the sum of the prefix minus adjustments allows valid construction, the condition holds. Time complexity is roughly (O(N^2 \log N)) due to sorting inside loops or pre-sorting with nested checks.

Approach B: Binary Search Optimization Since the feasibility condition exhibits monotonicity, binary search over the sorted array length reduces complexity. Locate the rightmost index where the value strictly exceeds 1.

C++ Implementation (Optimized)

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

void process_case() {
    int n;
    cin >> n;
    vector<int> data(n + 1);
    for (int i = 1; i <= n; ++i) cin >> data[i];
    
    sort(data.begin() + 1, data.end(), greater<int>());
    
    if (n == 1 && data[1] <= 1) {
        cout << ":-(" << "\n";
        return;
    }
    
    // Binary search for the valid segment end
    int left = 1, right = n, ans = -1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (data[mid] > 1) {
            ans = mid;
            right = mid - 1;
        } else {
            left = mid + 1;
        }
    }
    
    if (ans != -1) cout << "^_^" << "\n";
    else cout << ":-(" << "\n";
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    int t;
    if (cin >> t) {
        while(t--) process_case();
    }
    return 0;
}

Python Implementation

import sys
from bisect import bisect_left

def solve():
    input_data = sys.stdin.read().split()
    ptr = 0
    
    if ptr >= len(input_data): return
    n = int(input_data[ptr]); ptr += 1
    
    nums = [int(input_data[ptr + i]) for i in range(n)]
    ptr += n
    
    nums.sort(reverse=True)
    
    if n == 1:
        print(":-(")
        return
    
    # Find first element from left that is <= 1 implies invalid boundary
    # We want max index where val > 1 effectively
    # Since sorted desc, we look for last occurrence of > 1
    
    found = False
    for x in nums:
        if x > 1:
            found = True
            break
        else:
            break
            
    print("^_^" if found else ":-(")

if __name__ == "__main__":
    solve()

Problem 4: Scheduled Events

Objective: Manage cyclic scheduling constraints modulo a period.

Map event times (t) onto a cycle using (t \mod (a+b)). This transforms the circular constraint problem into a linear sliding window validation. Duplicate the sorted modulo array (adding the period (a+b) to the second half) to handle wrap-around cases seamlessly. Check all windows of size (n); if the difference between the maximum and minimum time in any window is less than (a), a valid schedule exists.

C++ Implementation

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

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    
    int n, a, b;
    if (!(cin >> n >> a >> b)) return 0;
    
    vector<int> events(n);
    int mod = a + b;
    for (int i = 0; i < n; ++i) {
        cin >> events[i];
        events[i] %= mod;
    }
    
    sort(events.begin(), events.end());
    
    // Expand to handle circularity
    vector<int> extended = events;
    for (int x : events) {
        extended.push_back(x + mod);
    }
    
    bool ok = false;
    for (int i = 0; i < n; ++i) {
        if (extended[i + n - 1] - extended[i] < a) {
            ok = true;
            break;
        }
    }
    
    cout << (ok ? "Yes" : "No") << "\n";
    return 0;
}

Python Implementation

import sys

def main():
    data = sys.stdin.read().split()
    if not data: return
    
    iterator = iter(data)
    n = int(next(iterator))
    a = int(next(iterator))
    b = int(next(iterator))
    
    mods = []
    for _ in range(n):
        mods.append(int(next(iterator)) % (a + b))
    
    mods.sort()
    doubled = mods + [x + a + b for x in mods]
    
    valid = False
    for i in range(n):
        if doubled[i + n - 1] - doubled[i] < a:
            valid = True
            break
    
    print("Yes" if valid else "No")

if __name__ == "__main__":
    main()

Problem 5: Prefix Sum Queries

Objective: Efficiently compute partial sums with varying step sizes.

Apply Square Root Decomposition technique. Divide queries into two categories based on step size (b):

  1. Large Steps ((b > \sqrt{N})): Perform direct traversal. Complexity per query (O(\sqrt{N})).
  2. Small Steps ((b \le \sqrt{N})): Precompute answers for all valid positions for each small step size. Complexity per query becomes nearly constant after (O(N\sqrt{N})) preprocessing.

Total Complexity: (O(N \sqrt{N})).

C++ Implementation

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

typedef long long ll;
struct Query { int id; int a; int b; };

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    
    int n; cin >> n;
    vector<ll> nums(n + 1);
    for (int i = 1; i <= n; ++i) cin >> nums[i];
    
    int q; cin >> q;
    vector<Query> qs(q);
    for (int i = 0; i < q; ++i) {
        cin >> qs[i].a >> qs[i].b;
        qs[i].id = i;
    }
    
    const int BLOCK_SIZE = 600;
    vector<vector<pair<int,int>>> small_qs(BLOCK_SIZE + 1);
    vector<pair<int,int>> large_qs;
    
    for (const auto& qry : qs) {
        if (qry.b <= BLOCK_SIZE) {
            small_qs[qry.b].push_back({qry.a, qry.id});
        } else {
            large_qs.push_back({qry.a, qry.id});
        }
    }
    
    vector<ll> results(q);
    
    // Process Small Steps
    for (int b = 1; b <= BLOCK_SIZE; ++b) {
        if (small_qs[b].empty()) continue;
        vector<ll> suffix_sum(n + 2, 0);
        for (int i = n; i >= 1; --i) {
            suffix_sum[i] = nums[i];
            if (i + b <= n) suffix_sum[i] += suffix_sum[i + b];
        }
        
        for (auto& p : small_qs[b]) {
            results[p.second] = suffix_sum[p.first];
        }
    }
    
    // Process Large Steps
    for (auto& p : large_qs) {
        ll current_sum = 0;
        int cur = p.first;
        int step = qs[p.second].b;
        while (cur <= n) {
            current_sum += nums[cur];
            cur += step;
        }
        results[p.second] = current_sum;
    }
    
    for (int i = 0; i < q; ++i) {
        cout << results[i] << "\n";
    }
    return 0;
}

Python Implementation

import sys

def solve():
    input_data = sys.stdin.read().split()
    if not input_data: return
    
    iterator = iter(input_data)
    n = int(next(iterator))
    arr = [0] * (n + 1)
    for i in range(1, n + 1):
        arr[i] = int(next(iterator))
    
    q = int(next(iterator))
    queries = []
    for k in range(q):
        a = int(next(iterator))
        b = int(next(iterator))
        queries.append((a, b, k))
    
    LIMIT = 550
    small_groups = [[] for _ in range(LIMIT + 1)]
    large_queries = []
    
    for a, b, idx in queries:
        if b <= LIMIT:
            small_groups[b].append((a, idx))
        else:
            large_queries.append((a, b, idx))
    
    answers = [0] * q
    
    # Small steps
    for b in range(1, LIMIT + 1):
        if not small_groups[b]: continue
        memo = [0] * (n + 5)
        for i in range(n, 0, -1):
            if i + b <= n:
                memo[i] = arr[i] + memo[i + b]
            else:
                memo[i] = arr[i]
        for a, idx in small_groups[b]:
            answers[idx] = memo[a]
            
    # Large steps
    for a, b, idx in large_queries:
        s = 0
        curr = a
        while curr <= n:
            s += arr[curr]
            curr += b
        answers[idx] = s
        
    print('\n'.join(map(str, answers)))

if __name__ == "__main__":
    solve()

Problem 6: Optimal Pratitioning

Objective: Maximize the score of partitioning an array into segments.

This is a Dynamic Programming problem optimized with advanced data structures. Define (dp_i) as the max score for the prefix of length (i). The transition is (dp_i = \max(dp_j + \text{value}(j+1, i))) where (1 \le j < i). The value function depends on whether the subarray sum (S_i - S_j) is positive, negative, or zero.

To optimize the (O(N^2)) DP transitions to (O(N \log N)):

  1. Coordinate compression is applied to prefix sums since values can be large.
  2. Three separate Fenwick Trees (or Segment Trees) maintain maximums for different term rearrangements: (dp_j), (dp_j - j), and (dp_j + j).
  3. Range maximum queries determine the optimal previous state efficiently.

C++ Implementation (BIT Version)

#include <iostream>
#include <vector>
#include <algorithm>
#define int long long
using namespace std;

const int INF = 0x3f3f3f3f3f3f3f3f;

struct BIT {
    int n;
    vector<int> tree;
    
    BIT(int size) : n(size), tree(size + 1, -INF) {}
    
    void update(int idx, int val) {
        while (idx <= n) {
            tree[idx] = max(tree[idx], val);
            idx += idx & (-idx);
        }
    }
    
    int query(int idx) {
        int res = -INF;
        while (idx > 0) {
            res = max(res, tree[idx]);
            idx -= idx & (-idx);
        }
        return res;
    }
};

signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    
    int n;
    cin >> n;
    vector<int> A(n + 1);
    vector<int> S(n + 1, 0);
    
    for (int i = 1; i <= n; ++i) {
        cin >> A[i];
        S[i] = S[i - 1] + A[i];
    }
    
    vector<int> coord = S;
    sort(coord.begin(), coord.end());
    coord.erase(unique(coord.begin(), coord.end()), coord.end());
    
    auto get_id = [&](int val) {
        return lower_bound(coord.begin(), coord.end(), val) - coord.begin() + 1;
    };
    
    int m = coord.size();
    BIT bit_plus(m), bit_minus(m), bit_zero(m + 1); 
    
    int id_0 = get_id(S[0]);
    bit_plus.update(id_0, 0);
    bit_minus.update(m - id_0 + 1, 0); // Reversed index logic for negative handling
    bit_zero.tree[id_0] = max(bit_zero.tree[id_0], 0); 
    
    int current_max = -INF;
    
    for (int i = 1; i <= n; ++i) {
        int id = get_id(S[i]);
        
        int opt1 = -INF, opt2 = -INF, opt3 = -INF;
        
        // Case: Sum > 0 (S[i] > S[j]) -> Query max(dp[j] - j)
        if (id > 1) opt1 = bit_plus.query(id - 1) + i;
        
        // Case: Sum = 0 (S[i] == S[j]) -> Query exact dp[j]
        opt2 = max(opt2, (int)bit_zero.tree[id]); 
        // Note: In full implementation, exact point query on BIT array needed or segtree
        // Simplified here for structure demonstration
        
        // Case: Sum < 0 (S[i] < S[j]) -> Query max(dp[j] + j)
        if (id < m) {
            opt3 = bit_minus.query(m - id + 1) - i; 
        }
        
        current_max = max({opt1, opt2, opt3});
        
        bit_plus.update(id, current_max - i);
        bit_minus.update(m - id + 1, current_max + i);
        bit_zero.tree[id] = max(bit_zero.tree[id], current_max);
    }
    
    cout << current_max << "\n";
    return 0;
}

Python Implementation

import sys

class BIT:
    def __init__(self, size):
        self.n = size
        self.tree = [-float('inf')] * (size + 1)

    def update(self, idx, val):
        while idx <= self.n:
            self.tree[idx] = max(self.tree[idx], val)
            idx += idx & (-idx)

    def query(self, idx):
        res = -float('inf')
        while idx > 0:
            res = max(res, self.tree[idx])
            idx -= idx & (-idx)
        return res

def solve():
    input_data = sys.stdin.read().split()
    if not input_data: return
    
    iterator = iter(input_data)
    n = int(next(iterator))
    A = []
    for _ in range(n):
        A.append(int(next(iterator)))
    
    S = [0] * (n + 1)
    for i in range(1, n + 1):
        S[i] = S[i - 1] + A[i - 1]
    
    coords = sorted(list(set(S)))
    rank_map = {v: i + 1 for i, v in enumerate(coords)}
    m = len(coords)
    
    bit_pos = BIT(m)
    bit_neg = BIT(m)
    
    s0_rank = rank_map[0]
    
    # Initial state
    bit_pos.update(s0_rank, 0)
    bit_neg.update(m - s0_rank + 1, 0)
    
    curr_dp = -float('inf')
    
    # Manual tracking for equal case (since standard BIT query prefix max doesn't support point equality easily without adjustment)
    # Using a simple map/array for exact matches in place of strict BIT optimization for clarity
    exact_vals = [-float('inf')] * (m + 1)
    exact_vals[s0_rank] = 0
    
    for i in range(1, n + 1):
        r = rank_map[S[i]]
        
        op1 = -float('inf')
        if r > 1:
            temp = bit_pos.query(r - 1)
            if temp > -float('inf'): op1 = temp + i
            
        op2 = -float('inf')
        if exact_vals[r] > -float('inf'): op2 = exact_vals[r]
            
        op3 = -float('inf')
        if r < m:
            temp = bit_neg.query(m - r + 1)
            if temp > -float('inf'): op3 = temp - i
            
        new_dp = max(op1, op2, op3)
        curr_dp = new_dp
        
        bit_pos.update(r, new_dp - i)
        bit_neg.update(m - r + 1, new_dp + i)
        exact_vals[r] = max(exact_vals[r], new_dp)
        
    print(curr_dp)

if __name__ == "__main__":
    solve()

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.