Programming Contest Problem Solutions: July 15, 2024

Problem 1: CF1607E

A straightforward problem that can be solved through direct simulation of the given process. The solution involves implementing the described algorithm step by step without requiring complex data structures or optimizations.

Problem 2: CF1614C

The solution leverages bitwise operations and segment trees to efficiently compute the result. By recognizing that bitwise operations on different bit positions are independent, we can process each bit separately and combine the results.

The key insight is to use a segment tree to apply bitwise AND operations over ranges, then calculate the contribution of each bit position to the final answer. The segment tree maintains a mask that represents the bitwise AND of all values in its range.

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

const int MAXN = 200000;
const int MOD = 1000000007;

int n, m;
int a[MAXN + 5];
int power[50];

struct SegmentTree {
    int tree[4 * MAXN];
    
    void build(int node, int start, int end) {
        tree[node] = (1 << 31) - 1;
        if (start == end) return;
        int mid = (start + end) / 2;
        build(2 * node, start, mid);
        build(2 * node + 1, mid + 1, end);
    }
    
    void update(int node, int start, int end, int l, int r, int value) {
        if (r < start || end < l) return;
        if (l <= start && end <= r) {
            tree[node] &= value;
            return;
        }
        int mid = (start + end) / 2;
        update(2 * node, start, mid, l, r, value);
        update(2 * node + 1, mid + 1, end, l, r, value);
    }
    
    void retrieve(int node, int start, int end) {
        if (start == end) {
            a[start] = tree[node];
            return;
        }
        int mid = (start + end) / 2;
        retrieve(2 * node, start, mid);
        retrieve(2 * node + 1, mid + 1, end);
    }
} segtree;

int calculateBitContribution(int bit) {
    int dp[2] = {1, 0};
    for (int i = 1; i <= n; i++) {
        bool hasBit = (a[i] >> bit) & 1;
        int newDp[2];
        newDp[0] = (dp[0] + dp[hasBit]) % MOD;
        newDp[1] = (dp[1] + dp[hasBit ^ 1]) % MOD;
        dp[0] = newDp[0];
        dp[1] = newDp[1];
    }
    return dp[1];
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    
    power[0] = 1;
    for (int i = 1; i < 40; i++) {
        power[i] = (power[i-1] * 2) % MOD;
    }
    
    int T;
    cin >> T;
    while (T--) {
        cin >> n >> m;
        segtree.build(1, 1, n);
        
        for (int i = 0; i < m; i++) {
            int l, r, v;
            cin >> l >> r >> v;
            segtree.update(1, 1, n, l, r, v);
        }
        
        segtree.retrieve(1, 1, n);
        int answer = 0;
        
        for (int bit = 0; bit < 31; bit++) {
            answer = (answer + calculateBitContribution(bit) * power[bit]) % MOD;
        }
        
        cout << answer << "\n";
    }
    
    return 0;
}
</vector></iostream>

Problem 3: CF1611G

This problem involves analyzing movement patterns on a chessboard. The board can be divided into two independent sets of squares (black and white) based on a checkerboard pattern. We can solve the problem separately for each set.

By transforming coordinates to (x+y, x-y), we convert the movement constraints into a monotonicity condition. The problem then reduces to finding the minimum number of increasing subsequences needed to cover all points, which can be solved greedily using a set to maintain the smallest possible ending values of subsequences.

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

const int MAXN = 1000000;

struct Point {
    int x, y;
};

vector<point> points[2];
int n, m;

bool comparePoints(const Point& p1, const Point& p2) {
    if (p1.x != p2.x) return p1.x < p2.x;
    return p1.y < p2.y;
}

int solveSet(vector<point>& pts) {
    sort(pts.begin(), pts.end(), comparePoints);
    set<int> ends;
    int subsequences = 0;
    
    if (!pts.empty()) {
        subsequences = 1;
        ends.insert(pts[0].y);
        
        for (size_t i = 1; i < pts.size(); i++) {
            auto it = ends.lower_bound(pts[i].y);
            if (it == ends.begin()) {
                subsequences++;
                ends.insert(pts[i].y);
            } else {
                it--;
                ends.erase(it);
                ends.insert(pts[i].y);
            }
        }
    }
    
    return subsequences;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int T;
    cin >> T;
    while (T--) {
        cin >> n >> m;
        points[0].clear();
        points[1].clear();
        
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                char c;
                cin >> c;
                if (c == '1') {
                    int color = (i + j) % 2;
                    points[color].push_back({i + j, i - j});
                }
            }
        }
        
        int result = solveSet(points[0]) + solveSet(points[1]);
        cout << result << "\n";
    }
    
    return 0;
}
</int></point></point></algorithm></set></vector></iostream>

Problem 4: Sequence with XOR Constraints

Given a sequence and a threshold x, we need to count the number of non-empty subsequences where the XOR of any two distinct elements is atleast x.

The solution involves: 1. Identifying the highest bit position in x (bst) 2. Grouping elements based on their bits from 60 down to bst 3. For each group, considering at most 2 elements (one with bst bit 0, one with bst bit 1) 4. Using a Trie to efficiently count valid pairs

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

const int MAXN = 100000;
const int MOD = 998244353;

struct TrieNode {
    int children[2];
    int count;
    
    TrieNode() {
        children[0] = children[1] = -1;
        count = 0;
    }
};

vector<trienode> trie;
int root;

void initTrie() {
    trie.clear();
    trie.emplace_back();
    root = 0;
}

void insert(int value, int bit) {
    int node = root;
    trie[node].count++;
    
    for (int i = bit; i >= 0; i--) {
        int bitValue = (value >> i) & 1;
        if (trie[node].children[bitValue] == -1) {
            trie[node].children[bitValue] = trie.size();
            trie.emplace_back();
        }
        node = trie[node].children[bitValue];
        trie[node].count++;
    }
}

int query(int value, int bit, int threshold) {
    int node = root;
    int result = 0;
    
    for (int i = bit; i >= 0; i--) {
        if (node == -1) break;
        
        int valueBit = (value >> i) & 1;
        int thresholdBit = (threshold >> i) & 1;
        
        if (thresholdBit == 0) {
            result = (result + trie[trie[node].children[valueBit ^ 1]].count) % MOD;
            node = trie[node].children[valueBit];
        } else {
            node = trie[node].children[valueBit ^ 1];
        }
    }
    
    if (node != -1) {
        result = (result + trie[node].count) % MOD;
    }
    
    return result;
}

int n, x;
vector<int> numbers;

int solveGroup(int bst) {
    initTrie();
    int count0 = 0, count1 = 0;
    
    for (int num : numbers) {
        if ((num >> bst) & 1) count1++;
        else count0++;
    }
    
    int result = 1 + count0 + count1;
    
    for (int num : numbers) {
        if (!((num >> bst) & 1)) {
            insert(num, bst);
        }
    }
    
    for (int num : numbers) {
        if ((num >> bst) & 1) {
            result = (result + query(num, bst, x)) % MOD;
        }
    }
    
    return result;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    
    cin >> n >> x;
    numbers.resize(n);
    
    for (int i = 0; i < n; i++) {
        cin >> numbers[i];
    }
    
    int highestBit = 0;
    int temp = x;
    while (temp) {
        if (temp & 1) highestBit = highestBit;
        temp >>= 1;
        highestBit++;
    }
    highestBit--;
    
    vector<vector>> groups;
    int currentGroup = 0;
    groups.emplace_back();
    
    for (int num : numbers) {
        int groupKey = num >> (highestBit + 1);
        if (currentGroup > 0 && groups[currentGroup-1][0] != groupKey) {
            currentGroup++;
            groups.emplace_back();
        }
        groups[currentGroup].push_back(num);
    }
    
    int answer = 1;
    for (const auto& group : groups) {
        numbers = group;
        answer = (answer * solveGroup(highestBit)) % MOD;
    }
    
    cout << (answer - 1 + MOD) % MOD << "\n";
    
    return 0;
}
</vector></int></trienode></algorithm></vector></iostream>

Tags: Competitive Programming segment tree Bitwise Operations chessboard problems XOR constraints

Posted on Sat, 29 Aug 2026 16:48:55 +0000 by sava