UKIEPC 2017 プログラミングコンテスト問題解説

Problem A: Alien Sunset

各惑星の自転周期、日の出時刻、日の入り時刻を格納します。自転周期の最大値(max_period)を求め、0からmax_period×1825までの時間を列挙します。各時間について全ての惑星で夜間であることを確認し、条件を満たす最初の時刻を出力します。

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

struct Planet {
    int period, sunrise, sunset;
};

int main() {
    int n, max_period = 0;
    cin >> n;
    vector<Planet> planets(n);
    for (int i = 0; i < n; i++) {
        cin >> planets[i].period >> planets[i].sunrise >> planets[i].sunset;
        max_period = max(max_period, planets[i].period);
    }

    for (int time = 0; time <= max_period * 1825; time++) {
        bool all_night = true;
        for (int j = 0; j < n; j++) {
            int local_time = time % planets[j].period;
            if (planets[j].sunrise < planets[j].sunset) {
                if (local_time > planets[j].sunrise && local_time < planets[j].sunset) {
                    all_night = false;
                    break;
                }
            } else {
                if (local_time < planets[j].sunset || local_time > planets[j].sunrise) {
                    all_night = false;
                    break;
                }
            }
        }
        if (all_night) {
            cout << time << endl;
            return 0;
        }
    }
    cout << "impossible" << endl;
    return 0;
}

Problem C: Cued In

貪欲法による解法です。各ボールの色と得点を対応付けた後、赤球の数をカウントします。赤球のみの場合は1点を出力し、それ以外の場合は(最高得点+1)×赤球数+その他のボール合計点を計算します。

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

int main() {
    int n;
    cin >> n;
    unordered_map<string, int> color_score = {
        {"red", 1}, {"yellow", 2}, {"green", 3},
        {"brown", 4}, {"blue", 5}, {"pink", 6}, {"black", 7}
    };
    int max_score = 0, total = 0, red_count = 0;
    for (int i = 0; i < n; i++) {
        string color;
        cin >> color;
        if (color == "red") red_count++;
        else {
            int score = color_score[color];
            total += score;
            max_score = max(max_score, score);
        }
    }
    if (red_count == n) cout << 1 << endl;
    else cout << (max_score + 1) * red_count + total << endl;
    return 0;
}

Problem D: Deranging Hat

文字列をソートし、元の文字列と比較します。各位置で文字が異なる場合、適切な位置と交換し交換インデックスを大きい順に出力します。

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

int main() {
    string original;
    cin >> original;
    string sorted = original;
    sort(sorted.begin(), sorted.end());
    for (int i = 0; i < sorted.size(); i++) {
        if (original[i] == sorted[i]) continue;
        for (int j = i + 1; j < sorted.size(); j++) {
            if (sorted[j] == original[i]) {
                if (sorted[i] < sorted[j]) cout << j + 1 << " " << i + 1 << endl;
                else cout << i + 1 << " " << j + 1 << endl;
                swap(sorted[i], sorted[j]);
                break;
            }
        }
    }
    return 0;
}

Problem E: Education

学生グループを降順に、部屋を家賃の昇順にソートします。各学生グループに収容可能な最小家賃の部屋を割り当てます。

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

int main() {
    int student_count, room_count;
    cin >> student_count >> room_count;
    vector<pair<int, int>> students;
    for (int i = 0; i < student_count; i++) {
        int size;
        cin >> size;
        students.push_back({size, i});
    }
    vector<tuple<int, int, int>> rooms;
    for (int i = 0; i < room_count; i++) {
        int capacity;
        cin >> capacity;
        rooms.push_back({capacity, 0, i});
    }
    for (int i = 0; i < room_count; i++) {
        int rent;
        cin >> rent;
        get<1>(rooms[i]) = rent;
    }

    sort(students.rbegin(), students.rend());
    sort(rooms.begin(), rooms.end(), [](auto &a, auto &b) {
        return get<1>(a) < get<1>(b);
    });

    vector<int> assignment(student_count);
    vector<bool> occupied(room_count, false);
    int assigned_count = 0;
    for (auto &[size, idx] : students) {
        bool found = false;
        for (int j = 0; j < room_count; j++) {
            auto &[cap, rent, id] = rooms[j];
            if (!occupied[j] && cap >= size) {
                occupied[j] = true;
                assignment[idx] = id + 1;
                assigned_count++;
                found = true;
                break;
            }
        }
        if (!found) break;
    }
    if (assigned_count != student_count) cout << "impossible" << endl;
    else for (int i = 0; i < student_count; i++) cout << assignment[i] << " \n"[i == student_count - 1];
    return 0;
}

Problem F: Flipping Coins

動的計画法で確率を計算します。dp[throws][heads]をthrows回投げたときheads個が表の確率と定義し、状態遷移を行います。最終的に期待値を計算します。

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

int main() {
    int coin_count, throw_count;
    cin >> coin_count >> throw_count;
    vector<vector<double>> dp(throw_count + 1, vector<double>(coin_count + 1, 0.0));
    dp[0][0] = 1.0;
    for (int i = 1; i <= throw_count; i++) {
        for (int j = 0; j <= coin_count; j++) {
            dp[i][j] += dp[i - 1][j] * 0.5;
            if (j > 0) dp[i][j] += dp[i - 1][j - 1] * 0.5;
            if (j == coin_count - 1) dp[i][j] += dp[i - 1][coin_count] * 0.5;
        }
    }
    double expectation = 0.0;
    for (int i = 0; i <= coin_count; i++) {
        expectation += i * dp[throw_count][i];
    }
    printf("%.8f\n", expectation);
    return 0;
}

Problem I: I Work All Day

各長さで木材長さを割った余りを計算し、最小余りを生成する長さを選択します。

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

int main() {
    int n;
    cin >> n;
    vector<int> lengths(n);
    for (int i = 0; i < n; i++) cin >> lengths[i];
    int wood_length;
    cin >> wood_length;
    int min_remainder = INT_MAX, result;
    for (int len : lengths) {
        int remainder = wood_length % len;
        if (remainder < min_remainder) {
            min_remainder = remainder;
            result = len;
        }
    }
    cout << result << endl;
    return 0;
}

Problem J: Just A Minim

入力値に対応する音符の長さを加算し、合計長さを出力します。

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

int main() {
    int n;
    cin >> n;
    double total = 0.0;
    unordered_map<int, double> length_map = {
        {0, 2.0}, {1, 1.0}, {2, 0.5}, {4, 0.25}, {8, 0.125}, {16, 0.0625}
    };
    for (int i = 0; i < n; i++) {
        int note;
        cin >> note;
        total += length_map[note];
    }
    printf("%.6f\n", total);
    return 0;
}

タグ: enumeration greedy Sorting dynamic-programming probability

7月15日 16:15 投稿