Algorithm Solutions for Codeforces Educational Round 164

A. Ribbon Coloring Strategy

Alice's optimal strategy is to color the ribbon in a repeating pattern like "123123...". Bob's optimal counter-strategy is to recolor the ribbon to the most frequent color.

The most frequent color appears at least ⌈n/m⌉ times, leaving Bob with at most (n - ⌈n/m⌉) recoloring operations. Compare this value with k to determine the winner.

#include <iostream>
using namespace std;

int main() {
    int testCases;
    cin >> testCases;
    while (testCases--) {
        int length, colors, maxOperations;
        cin >> length >> colors >> maxOperations;
        int maxColorCount = (length + colors - 1) / colors;
        cout << (length - maxColorCount > maxOperations ? "YES" : "NO") << endl;
    }
    return 0;
}

B. Minimum Removal for Ugly Sequence

A beautiful sequence consists of blocks of 'a's separated by single 'b's. To make it non-beautiful, we need to create adjacent 'b's by removing the shortest continuous block of 'a's between two 'b's.

The solution finds the minimal length of consecutive iedntical elements matching the first element.

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

int main() {
    int testCases;
    cin >> testCases;
    while (testCases--) {
        int sequenceLength;
        cin >> sequenceLength;
        vector<int> elements(sequenceLength);
        for (int i = 0; i < sequenceLength; i++) {
            cin >> elements[i];
        }
        
        int currentStreak = 0;
        int minStreak = sequenceLength + 1;
        for (int i = 0; i < sequenceLength; i++) {
            if (elements[i] == elements[0]) {
                currentStreak++;
            } else {
                minStreak = min(minStreak, currentStreak);
                currentStreak = 0;
            }
        }
        minStreak = min(minStreak, currentStreak);
        
        cout << (minStreak == sequenceLength ? -1 : minStreak) << endl;
    }
    return 0;
}

C. Optimal Number Assignment

Given two numbers with equal digit counts, rearrange digits to minimize their product while maintaining the sum. The optimal approach distributes digits to make the numbers as close as possible.

Identify the highest differing digit position. Assign larger remaining digits to the smaller number and smaller digits to the larger number from that position onward.

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

int main() {
    int testCases;
    cin >> testCases;
    while (testCases--) {
        string num1, num2;
        cin >> num1 >> num2;
        
        if (num1 < num2) swap(num1, num2);
        
        bool foundDifference = false;
        for (int i = 0; i < num1.length(); i++) {
            if (num1[i] > num2[i]) {
                if (foundDifference) swap(num1[i], num2[i]);
                else foundDifference = true;
            }
        }
        
        cout << num1 << endl << num2 << endl;
    }
    return 0;
}

D. Ball Grouping Combinations

Use dynamic programming where f[k] represents the number of ways to achieve sum k. For each ball count a_i, calculate contributions based on whether a_i exceeds current sum k.

When a_i > k, contribution is a_i per way. Otherwise, contribution is ⌈(k + a_i)/2⌉ per way. Update the DP table after processing each ball.

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

const int MOD = 998244353;
const int MAX_SUM = 5000;

int main() {
    int ballTypes;
    cin >> ballTypes;
    vector<int> balls(ballTypes);
    for (int i = 0; i < ballTypes; i++) {
        cin >> balls[i];
    }
    
    sort(balls.begin(), balls.end());
    vector<int> dp(MAX_SUM + 1, 0);
    dp[0] = 1;
    long long total = 0;
    
    for (int i = 0; i < ballTypes; i++) {
        int currentBall = balls[i];
        for (int sum = 0; sum <= currentBall; sum++) {
            total = (total + 1LL * dp[sum] * currentBall) % MOD;
        }
        for (int sum = currentBall + 1; sum <= MAX_SUM; sum++) {
            total = (total + 1LL * dp[sum] * ((sum + currentBall + 1) / 2)) % MOD;
        }
        
        for (int sum = MAX_SUM; sum >= currentBall; sum--) {
            dp[sum] = (dp[sum] + dp[sum - currentBall]) % MOD;
        }
    }
    
    cout << total << endl;
    return 0;
}

E. Chain Reaction Analysis

Define f[i] as the number of remaining connected segments after removing all elements with values ≤ i. For each step size t, the answer is the sum of f[t×i] for i from 0 to ⌈m/t⌉.

Precompute f by tracking segment splits and merges as elements are removed layer by layer.

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

const int MAX_VALUE = 100000;

int main() {
    int elementCount;
    cin >> elementCount;
    vector<int> values(elementCount);
    vector<vector<int>> valuePositions(MAX_VALUE + 1);
    vector<bool> active(elementCount + 2, true);
    
    int maxValue = 0;
    for (int i = 0; i < elementCount; i++) {
        cin >> values[i];
        maxValue = max(maxValue, values[i]);
        valuePositions[values[i]].push_back(i + 1);
    }
    
    vector<int> segmentCount(maxValue + 1);
    int currentSegments = 1;
    segmentCount[0] = currentSegments;
    
    for (int value = 1; value <= maxValue; value++) {
        for (int position : valuePositions[value]) {
            if (active[position - 1] && active[position + 1]) {
                currentSegments++;
            } else if (!active[position - 1] && !active[position + 1]) {
                currentSegments--;
            }
            active[position] = false;
        }
        segmentCount[value] = currentSegments;
    }
    
    for (int step = 1; step <= maxValue; step++) {
        long long result = 0;
        for (int multiple = 0; multiple <= maxValue; multiple += step) {
            result += segmentCount[multiple];
        }
        cout << result << " ";
    }
    
    return 0;
}

Tags: dynamic-programming greedy-algorithm combinatorics number-theory algorithm-analysis

Posted on Fri, 19 Jun 2026 16:00:53 +0000 by []InTeR[]