Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Competitive Programming Solutions: Mathematical Analysis, Matrix Operations, Bracket Sequences, and DAG Construction

Tech 1

Problem A: Minimum Function Summation

Given the function f(x) = min_{i∈ℕ⁺}, compute the sum Σ_{i=1}^{n} f(i) modulo 10^9+7 across multiple test cases.

Constraints: n ≤ 10^16, T ≤ 10^4.

Solution Approach:

Analyze the frequency of each value in the sequence f(i). For a particular value x, we need to count integers i satisfying:

  • i mod x ≠ 0
  • i mod y = 0 for some y ∈ [2, x)

The second condition implies divisibility by lcm(2, 3, ..., x-1). Let t = lcm(2, ..., x-1). The count of numbers satisfying both conditions equals:

⌊n/t⌋ - ⌊n/lcm(t, x)⌋

Implementation:

#include <bits/stdc++.h>
using ll = long long;
const int MOD = 1000000007;

ll solve(ll n) {
    ll result = 0;
    for (ll i = 2, curLcm = 1, newLcm; curLcm <= n; ++i) {
        newLcm = curLcm / std::gcd(curLcm, i) * i;
        result = (result + ((n / curLcm - n / newLcm) % MOD) * i) % MOD;
        curLcm = newLcm;
    }
    return result;
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int T;
    std::cin >> T;
    while (T--) {
        ll n;
        std::cin >> n;
        std::cout << solve(n) << '\n';
    }
    return 0;
}

Problem B: DZY Loves Modification

Rating: 2000

Given an n×m matrix. Perform k operations where each operation selects either a row or column, adds its sum to the total score, and subtracts p from every cell in that row or column. Maximize the final score.

Constraints: n, m, a_{i,j} ≤ 10^3, k ≤ 10^6, 1 ≤ p ≤ 100.

Solution Approach:

The order of operations doesn't affect optimality. If we select i rows and (k-i) columns, the penalty deducted equals i·(k-i)·p.

Precompute initial row sums and column sums. Use two max-heaps to simulate repeatedly taking the maximum row/column sum, with each extraction reducing future values by p times the opposite dimension.

Implementation:

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

int main() {
    int n, m, k;
    ll p;
    std::cin >> n >> m >> k >> p;
    
    std::vector<ll> rowSum(n + 1, 0), colSum(m + 1, 0);
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            int x;
            std::cin >> x;
            rowSum[i] += x;
            colSum[j] += x;
        }
    }
    
    std::priority_queue<ll> rowPQ, colPQ;
    for (int i = 1; i <= n; ++i) rowPQ.push(rowSum[i]);
    for (int j = 1; j <= m; ++j) colPQ.push(colSum[j]);
    
    std::vector<ll> rowDP(k + 1, 0), colDP(k + 1, 0);
    for (int i = 1; i <= k; ++i) {
        ll cur = rowPQ.top(); rowPQ.pop();
        rowDP[i] = rowDP[i - 1] + cur;
        rowPQ.push(cur - p * m);
    }
    
    for (int i = 1; i <= k; ++i) {
        ll cur = colPQ.top(); colPQ.pop();
        colDP[i] = colDP[i - 1] + cur;
        colPQ.push(cur - p * n);
    }
    
    ll answer = LLONG_MIN;
    for (int i = 0; i <= k; ++i) {
        ll total = rowDP[i] + colDP[k - i] - 1LL * i * (k - i) * p;
        answer = std::max(answer, total);
    }
    
    std::cout << answer << '\n';
    return 0;
}

Problem C: RBS

Rating: 2400

Given n bracket strings, concatenate them in any order to maximize the number of valid bracket sequence prefixes in the final string.

Constraints: n ≤ 20, Σ|s| ≤ 4×10^5.

Solution Approach:

For a string s, define:

  • balance[i]: cumulative balance after position i
  • minBal[i]: minimum balance over prefix [0, i]

When concatenating string s with current balance b, s is valid if minBal[i] + b ≥ 0 for all i. The number of valid prefixes equals count of positions where balance[i] ≥ -b.

Use segment trees for range queries and DP over subsets with state (mask, lastBalance). Complexity: O(n · 2^n · log n).

Implementation:

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

struct PersistentSegTree {
    struct Node {
        int left, right, cnt;
    };
    vector<Node> tree;
    
    void init(int sz) {
        tree.resize(sz * 6);
    }
    
    void update(int& idx, int prev, int l, int r, int pos) {
        idx = ++tree[0].cnt;
        tree[idx] = tree[prev];
        if (l == r) {
            tree[idx].cnt++;
            return;
        }
        int mid = (l + r) >> 1;
        if (pos <= mid) update(tree[idx].left, tree[prev].left, l, mid, pos);
        else update(tree[idx].right, tree[prev].right, mid + 1, r, pos);
        tree[idx].cnt = tree[tree[idx].left].cnt + tree[tree[idx].right].cnt;
    }
    
    int query(int idx, int l, int r, int pos) {
        if (!idx) return 0;
        if (l == r) return tree[idx].cnt;
        int mid = (l + r) >> 1;
        return pos <= mid ? query(tree[idx].left, l, mid, pos) 
                          : query(tree[idx].right, mid + 1, r, pos);
    }
};

struct BracketString {
    int len, offset;
    vector<int> pref, minPref;
    vector<int> roots;
    PersistentSegTree seg;
    
    void build(const string& s) {
        len = s.length();
        pref.resize(len);
        minPref.resize(len);
        roots.resize(len);
        seg.init(len);
        seg.tree[0].cnt = 0;
        seg.tree[0].left = seg.tree[0].right = 0;
        
        int cur = 0;
        for (int i = 0; i < len; ++i) {
            cur += (s[i] == '(' ? 1 : -1);
            pref[i] = cur;
        }
        
        cur = 0;
        for (int i = len - 1; i >= 0; --i) {
            cur = min(cur, pref[i]);
            minPref[i] = cur;
        }
        offset = len;
        
        for (int i = 0; i < len; ++i) {
            seg.update(roots[i], i ? roots[i - 1] : 0, 0, len + len, pref[i] + offset);
        }
    }
    
    int findLastValid(int balance) {
        int target = -balance;
        int lo = 0, hi = len - 1, pos = -1;
        while (lo <= hi) {
            int mid = (lo + hi) >> 1;
            if (minPref[mid] >= target) {
                pos = mid;
                lo = mid + 1;
            } else {
                hi = mid - 1;
            }
        }
        return pos;
    }
    
    int countValidPrefix(int lastPos, int balance) {
        if (lastPos < 0 || balance + offset < 0) return 0;
        return seg.query(lastPos >= 0 ? roots[lastPos] : 0, 0, len + len, balance + offset);
    }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n;
    cin >> n;
    vector<BracketString> S(n);
    
    for (int i = 0; i < n; ++i) {
        string s;
        cin >> s;
        S[i].build(s);
    }
    
    const int LIM = 1 << n;
    vector<int> dp(LIM, INT_MIN), finalBal(LIM, 0);
    dp[0] = 0;
    int answer = 0;
    
    for (int mask = 1; mask < LIM; ++mask) {
        for (int j = 0; j < n; ++j) {
            if (mask & (1 << j)) {
                finalBal[mask] = finalBal[mask ^ (1 << j)] + S[j].pref.back();
                break;
            }
        }
        
        for (int j = 0; j < n; ++j) {
            if (!(mask & (1 << j))) continue;
            
            int prevMask = mask ^ (1 << j);
            int lastPos = S[j].findLastValid(finalBal[prevMask]);
            int validCount = dp[prevMask] + S[j].countValidPrefix(lastPos, finalBal[prevMask]);
            
            answer = max(answer, validCount);
            
            if (lastPos == S[j].len - 1) {
                dp[mask] = max(dp[mask], validCount);
            }
        }
        answer = max(answer, dp[mask]);
    }
    
    cout << answer << '\n';
    return 0;
}

Problem D: DAG Path Construction

Construct a directed acyclic graph (DAG) with vertices numbered 1 to 114 such that:

  • The number of distinct paths from vertex 1 to vertex 114 equals n + 1
  • Each integer in [0, n] appears exactly once as the total edge weight sum of some path

Constraints: edge weights are non-negative integers, n ≤ 32500. A solution exists with at most 18 vertices and 45 edges, with maximum edge weight ≤ n.

Solution Approach:

This constructive problem can be solved using combinatorial number system representation. The key insight is that any integer in [0, n] can be uniquely represented as a sum of binomial coefficients:

x = C(a₁, 1) + C(a₂, 2) + ... + C(a_k, k), where a₁ < a₂ < ... < a_k

This representation ensures exactly one path for each weight value. Construct vertices representing positions in this combinatorial expansion, with edges weighted according to binomial coefficients.

Implementation:

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

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n;
    cin >> n;
    
    vector<int> binom;
    for (int i = 1; i <= n + 5; ++i) {
        long long val = 1;
        for (int j = 1; j <= i && val <= n; ++j) {
            val = val * (n + i) / j;
            if (val > n) break;
        }
        if (val <= n) binom.push_back(val);
    }
    
    cout << 18 << ' ' << 44 << '\n';
    
    for (int i = 2; i <= 17; ++i) {
        cout << 1 << ' ' << i << ' ' << (i == 2 ? 0 : binom[i - 3]) << '\n';
    }
    
    for (int i = 2; i <= 17; ++i) {
        for (int j = i + 1; j <= 17; ++j) {
            if (j - i == 1) {
                cout << i << ' ' << j << ' ' << 0 << '\n';
            }
        }
    }
    
    cout << 18 << ' ' << 114 << ' ' << 0 << '\n';
    
    return 0;
}

The construction leverages the uniqueness of combinatorial number system representation to ensure each weight from 0 to n appears exactly once across all paths from source to destination.

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.