C++プログラミングコンテスト問題集と解答例

L1-1 挨拶出力

解法

指定されたテキストをそのまま出力する。

実装例

#include <iostream>
using namespace std;

int main() {
    cout << "ありがとう!\\(>_<)/" << endl;
    return 0;
}

L1-2 平均速度計算

実装例

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

int main() {
    int distance, time;
    cin >> distance >> time;
    
    double speed = static_cast<double>(distance) / time;
    cout << fixed << setprecision(3) << speed << endl;
    
    return 0;
}

L1-3 ポイント集計

実装例

#include <iostream>
using namespace std;

int main() {
    int count;
    cin >> count;
    
    int total = 0;
    for (int i = 0; i < count; i++) {
        int value;
        cin >> value;
        
        if (value < 100) total += 1;
        else if (value < 200) total += 2;
        else if (value < 300) total += 5;
        else if (value < 400) total += 10;
        else total += 15;
    }
    
    cout << total << endl;
    return 0;
}

L1-4 マインスイーパ

実装例

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

int main() {
    int rows, cols;
    cin >> rows >> cols;
    
    vector<string> grid(rows);
    for (int i = 0; i < rows; i++) {
        cin >> grid[i];
    }
    
    int dx[] = {-1, -1, -1, 0, 0, 1, 1, 1};
    int dy[] = {-1, 0, 1, -1, 1, -1, 0, 1};
    
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            if (grid[i][j] == '*') {
                cout << '*';
            } else {
                int mines = 0;
                for (int k = 0; k < 8; k++) {
                    int ni = i + dx[k];
                    int nj = j + dy[k];
                    if (ni >= 0 && ni < rows && nj >= 0 && nj < cols) {
                        if (grid[ni][nj] == '*') {
                            mines++;
                        }
                    }
                }
                cout << (mines == 0 ? '.' : char('0' + mines));
            }
        }
        cout << endl;
    }
    
    return 0;
}

L1-5 文字列圧縮

実装例

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

int main() {
    int length;
    string input;
    cin >> length >> input;
    
    string result;
    for (int i = 0; i < length; i++) {
        if (i == 0 || input[i] != input[i-1]) {
            result += input[i];
        }
    }
    
    cout << result.size() << endl;
    cout << result << endl;
    
    return 0;
}

L1-6 暗号化処理

実装例

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

int main() {
    int n, shift;
    string text;
    cin >> n >> shift >> text;
    
    vector<int> mapping(26);
    for (int i = 0; i < 26; i++) {
        cin >> mapping[i];
    }
    
    for (int i = 0; i < n; i++) {
        int pos = (i - shift + n) % n;
        cout << mapping[text[pos] - 'a'];
    }
    
    return 0;
}

L1-7 文字列操作

実装例

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

int main() {
    int n;
    string str;
    cin >> n >> str;
    
    int queries;
    cin >> queries;
    
    bool swapped = false;
    while (queries--) {
        int type, idx1, idx2;
        cin >> type >> idx1 >> idx2;
        
        if (type == 1) {
            if (!swapped) {
                swap(str[idx1], str[idx2]);
            } else {
                swap(str[(idx1 + n) % (2*n)], str[(idx2 + n) % (2*n)]);
            }
        } else {
            swapped = !swapped;
        }
    }
    
    if (swapped) {
        str = str.substr(n) + str.substr(0, n);
    }
    
    cout << str << endl;
    return 0;
}

L1-8 成績ランキング

実装例

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

int main() {
    int students, limit;
    cin >> students >> limit;
    
    vector<pair<double, string>> scores;
    for (int i = 0; i < students; i++) {
        string name;
        double score1;
        int score2, score3, qualified;
        cin >> name >> score1 >> score2 >> score3 >> qualified;
        
        if (qualified) {
            score1 = score1 * 10 + 50;
            score2 = min(score2 + 70, 100);
            double final_score = (score1 + score3) * 0.7 + score2 * 0.3;
            scores.emplace_back(final_score, name);
        }
    }
    
    sort(scores.begin(), scores.end(), [](auto& a, auto& b) {
        if (a.first == b.first) return a.second < b.second;
        return a.first > b.first;
    });
    
    cout << fixed << setprecision(1);
    int current_rank = 0;
    for (int i = 0; i < scores.size(); i++) {
        current_rank = i + 1;
        if (current_rank > limit) break;
        
        cout << current_rank << " " << scores[i].second << " " << scores[i].first << endl;
        
        while (i + 1 < scores.size() && scores[i+1].first == scores[i].first) {
            i++;
            cout << current_rank << " " << scores[i].second << " " << scores[i].first << endl;
        }
    }
    
    return 0;
}

L2-1 ネットワーク接続

実装例

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

class UnionFind {
private:
    vector<int> parent, rank;
public:
    UnionFind(int n) {
        parent.resize(n);
        rank.assign(n, 0);
        iota(parent.begin(), parent.end(), 0);
    }
    
    int find(int x) {
        return parent[x] == x ? x : parent[x] = find(parent[x]);
    }
    
    void unite(int x, int y) {
        int rootX = find(x);
        int rootY = find(y);
        if (rootX == rootY) return;
        
        if (rank[rootX] < rank[rootY]) {
            parent[rootX] = rootY;
        } else if (rank[rootX] > rank[rootY]) {
            parent[rootY] = rootX;
        } else {
            parent[rootY] = rootX;
            rank[rootX]++;
        }
    }
    
    bool connected(int x, int y) {
        return find(x) == find(y);
    }
};

int main() {
    int nodes, edges, queries;
    cin >> nodes >> edges >> queries;
    
    UnionFind uf(nodes + 1);
    for (int i = 0; i < edges; i++) {
        int a, b;
        cin >> a >> b;
        uf.unite(a, b);
    }
    
    for (int i = 0; i < queries; i++) {
        int a, b;
        cin >> a >> b;
        cout << (uf.connected(a, b) ? "yes" : "no") << endl;
    }
    
    int components = 0;
    for (int i = 1; i <= nodes; i++) {
        if (uf.find(i) == i) {
            components++;
        }
    }
    cout << components << endl;
    
    return 0;
}

L2-2 問題割り当て

実装例

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

int main() {
    int n;
    cin >> n;
    
    vector<int> required(10), available(10);
    for (int i = 0; i < 10; i++) {
        cin >> required[i];
    }
    
    vector<vector<array<int, 3>>> problems(10);
    for (int i = 1; i <= n; i++) {
        int k;
        cin >> k;
        while (k--) {
            char ch;
            int level, number;
            cin >> ch >> level >> ch >> number;
            level--;
            problems[level].push_back({level, i, number});
            available[level]++;
        }
    }
    
    for (auto& level_problems : problems) {
        reverse(level_problems.begin(), level_problems.end());
    }
    
    vector<array<int, 3>> result;
    
    auto assign_problems = [&](int target_level, int source_level) {
        while (required[target_level] > 0 && available[source_level] > 0) {
            result.push_back(problems[source_level].back());
            problems[source_level].pop_back();
            required[target_level]--;
            available[source_level]--;
        }
    };
    
    for (int level = 0; level < 10; level++) {
        assign_problems(level, level);
        
        if (required[level] > 0) {
            for (int offset = 1; offset < 10; offset++) {
                if (level + offset < 10 && available[level + offset] > 0) {
                    assign_problems(level, level + offset);
                }
            }
            for (int offset = 1; offset < 10; offset++) {
                if (level - offset >= 0 && available[level - offset] > 0) {
                    assign_problems(level, level - offset);
                }
            }
        }
    }
    
    sort(result.begin(), result.end());
    for (int i = 0; i < result.size(); i++) {
        auto& item = result[i];
        cout << item[1] << '-' << item[2];
        if (i == result.size() - 1) cout << endl;
        else cout << " ";
    }
    
    return 0;
}

L2-3 数字操作DP

実装例

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

const int MOD = 998244353;

int main() {
    int n;
    cin >> n;
    
    vector<int> nums(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> nums[i];
    }
    
    vector<long long> dp(10, 0);
    dp[(nums[1] + nums[2]) % 10] += 1;
    dp[(nums[1] * nums[2]) % 10] += 1;
    
    for (int i = 3; i <= n; i++) {
        vector<long long> new_dp(10, 0);
        for (int j = 0; j < 10; j++) {
            if (dp[j] > 0) {
                new_dp[(j + nums[i]) % 10] = (new_dp[(j + nums[i]) % 10] + dp[j]) % MOD;
                new_dp[(j * nums[i]) % 10] = (new_dp[(j * nums[i]) % 10] + dp[j]) % MOD;
            }
        }
        dp = new_dp;
    }
    
    for (int i = 0; i < 10; i++) {
        cout << dp[i] << endl;
    }
    
    return 0;
}

L2-4 最短解放時間

実装例

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

int main() {
    int n, m, start;
    cin >> n >> m >> start;
    
    vector<int> unlock_time(n + 1);
    for (int i = 1; i <= n; i++) {
        int node;
        cin >> node;
        unlock_time[node] = i;
    }
    
    vector<vector<int>> graph(n + 1);
    for (int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v;
        graph[u].push_back(v);
        graph[v].push_back(u);
    }
    
    vector<int> earliest_time(n + 1, 0);
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
    pq.push({unlock_time[start], start});
    
    while (!pq.empty()) {
        auto [time, node] = pq.top();
        pq.pop();
        
        if (earliest_time[node] != 0) continue;
        earliest_time[node] = time;
        
        for (int neighbor : graph[node]) {
            int new_time = max(unlock_time[neighbor], time);
            if (earliest_time[neighbor] == 0 || new_time < earliest_time[neighbor]) {
                pq.push({new_time, neighbor});
            }
        }
    }
    
    for (int i = 1; i <= n; i++) {
        cout << earliest_time[i];
        if (i == n) cout << endl;
        else cout << " ";
    }
    
    return 0;
}

L3-1 素因数経路探索

実装例

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

const int MAX_N = 1000000;
const int INF = 1e9;

int main() {
    int n;
    cin >> n;
    
    vector<int> nodes(n + 1);
    vector<bool> exists(MAX_N + 1, false);
    for (int i = 1; i <= n; i++) {
        cin >> nodes[i];
        exists[nodes[i]] = true;
    }
    
    vector<vector<pair<int, int>>> graph(2 * MAX_N + 10);
    
    vector<bool> is_prime(MAX_N + 1, true);
    for (int i = 2; i <= MAX_N; i++) {
        if (is_prime[i]) {
            for (int j = i; j <= MAX_N; j += i) {
                if (exists[j]) {
                    int weight = j / i;
                    graph[j].emplace_back(weight, i + MAX_N);
                    graph[i + MAX_N].emplace_back(weight, j);
                }
                if (j > i) is_prime[j] = false;
            }
        }
    }
    
    int start, end;
    cin >> start >> end;
    
    if (start == end) {
        cout << 0 << endl << start << endl;
        return 0;
    }
    
    vector<int> distance(2 * MAX_N + 10, INF);
    vector<int> previous(2 * MAX_N + 10, -1);
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
    
    distance[start] = 0;
    pq.push({0, start});
    
    while (!pq.empty()) {
        auto [dist, current] = pq.top();
        pq.pop();
        
        if (current == end) break;
        if (dist > distance[current]) continue;
        
        for (auto [weight, neighbor] : graph[current]) {
            int new_dist = distance[current] + weight;
            if (new_dist < distance[neighbor]) {
                distance[neighbor] = new_dist;
                previous[neighbor] = current;
                pq.push({new_dist, neighbor});
            }
        }
    }
    
    if (distance[end] == INF) {
        cout << "目的地に到達不可" << endl << "-1" << endl;
        return 0;
    }
    
    vector<int> full_path;
    for (int node = end; node != -1; node = previous[node]) {
        full_path.push_back(node);
    }
    reverse(full_path.begin(), full_path.end());
    
    vector<int> actual_path;
    for (int node : full_path) {
        if (node <= MAX_N) {
            actual_path.push_back(node);
        }
    }
    
    cout << distance[end] << endl;
    for (int i = 0; i < actual_path.size(); i++) {
        cout << actual_path[i];
        if (i == actual_path.size() - 1) cout << endl;
        else cout << " ";
    }
    
    return 0;
}

タグ: C++ 競技プログラミング アルゴリズム データ構造 グラフ理論

6月10日 20:29 投稿