2023年伝智杯プログラミング競技予選ソリューション

文字列連結

2つの文字列を入力として受け取り、連結して出力します。空白を含む可能性があるため、getline関数を使用します。

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

int main() {
    string a, b;
    getline(cin, a);
    getline(cin, b);
    cout << a + b;
    return 0;
}

最小差分値

整数配列内の隣接要素間の最小差分値を求めます。配列をソート後、隣接要素間の差を計算します。

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

int main() {
    int n;
    cin >> n;
    vector<int> arr(n);
    for (int i = 0; i < n; i++) cin >> arr[i];
    sort(arr.begin(), arr.end());
    int minDiff = INT_MAX;
    for (int i = 1; i < n; i++) {
        minDiff = min(minDiff, arr[i] - arr[i-1]);
    }
    cout << minDiff;
}

グリッド色分けゲーム

n×mグリッドの色分けゲームで、両次元が奇数の場合に先手が勝利します。中心セル戦略により決定されます。

#include <iostream>
using namespace std;

int main() {
    int n, m;
    cin >> n >> m;
    if (n % 2 && m % 2) cout << "akai";
    else cout << "yukari";
    return 0;
}

abb部分列カウント

文字列内のabb形式(例: "abb")の部分列をカウントします。各位置の後に出現する文字の頻度を記録し、組合せ計算を行います。

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

int main() {
    int n;
    string s;
    cin >> n >> s;
    vector<vector<long>> freq(n+1, vector<long>(26));
    for (int i = n-1; i >= 0; i--) {
        freq[i] = freq[i+1];
        freq[i][s[i]-'a']++;
    }
    long result = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < 26; j++) {
            if (j == s[i]-'a') continue;
            long count = freq[i+1][j];
            result += count * (count - 1) / 2;
        }
    }
    cout << result;
}

素因数選択最小和

各数値から一意の素因数を選択し、和の最小値を求めます。深さ優先探索で全ての組合せを探索します。

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

const int primes[] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97};
vector<vector<int>> factors;
vector<bool> used(25, false);
int minSum = INT_MAX;

void dfs(int idx, int currSum, int total) {
    if (idx == total) {
        minSum = min(minSum, currSum);
        return;
    }
    for (int f : factors[idx]) {
        if (used[f]) continue;
        used[f] = true;
        dfs(idx+1, currSum + primes[f], total);
        used[f] = false;
    }
}

int main() {
    int n;
    cin >> n;
    factors.resize(n);
    for (int i = 0; i < n; i++) {
        int num;
        cin >> num;
        for (int j = 0; j < 25; j++) {
            if (num % primes[j] != 0) continue;
            factors[i].push_back(j);
            while (num % primes[j] == 0) num /= primes[j];
        }
    }
    dfs(0, 0, n);
    cout << (minSum == INT_MAX ? -1 : minSum);
}

二分木色分け問題

木構造のノードを赤/青で塗り分け、隣接ノードが異なる色になるよう割り当てます。葉ノードから親子ペアを決定します。

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

vector<vector<int>> graph;
vector<int> color;
vector<int> groupId;
int groupCount = 0;
bool valid = true;

void buildPairs(int node, int parent) {
    int children = 0;
    for (int child : graph[node]) {
        if (child == parent) continue;
        children++;
        buildPairs(child, node);
    }
    if (children == 0 || groupId[node] == 0) {
        if (groupId[parent] != 0) valid = false;
        groupId[node] = groupId[parent] = ++groupCount;
    }
}

void assignColors(int node, int parent) {
    for (int child : graph[node]) {
        if (child == parent) continue;
        if (groupId[child] == groupId[node]) color[child] = color[node];
        else color[child] = !color[node];
        assignColors(child, node);
    }
}

int main() {
    int n;
    cin >> n;
    graph.resize(n+1);
    color.resize(n+1);
    groupId.resize(n+1);
    for (int i = 1; i < n; i++) {
        int u, v;
        cin >> u >> v;
        graph[u].push_back(v);
        graph[v].push_back(u);
    }
    buildPairs(1, 0);
    if (!valid || groupId[0] != 0) {
        cout << -1;
        return 0;
    }
    color[1] = 1;
    assignColors(1, 0);
    for (int i = 1; i <= n; i++) 
        cout << (color[i] ? 'R' : 'B');
}

タグ: アルゴリズム 競技プログラミング C++ グラフ理論 動的計画法

6月4日 19:44 投稿