問題A: ゲームの点数計算
木青チームと高橋チームの点数をそれぞれ計算し、木青チームの総得点が高橋チームより1点多くなるようにします。
コード例
#include <iostream>
#include <vector>
int main() {
int score_gq = 0, score_mq = 0;
int input;
// 木青チームの9つの点数を入力
for (int i = 0; i < 9; ++i) {
std::cin >> input;
score_gq += input;
}
// 高橋チームの8つの点数を入力
for (int i = 0; i < 8; ++i) {
std::cin >> input;
score_mq += input;
}
// 木青チームの点数が1点多くなるように調整
std::cout << score_gq - score_mq + 1 << std::endl;
return 0;
}
問題B: グリッドの不一致箇所
2つのn×nのグリッドを比較し、最初に不一致となるセルの位置(行と列)を見つけます。
コード例
#include <iostream>
#include <vector>
int main() {
int n;
std::cin >> n;
std::vector grid1(n), grid2(n);
// 最初のグリッドを読み込む
for (int i = 0; i < n; ++i) {
std::cin >> grid1[i];
}
// 2つ目のグリッドを読み込み、不一致を探す
for (int i = 0; i < n; ++i) {
std::cin >> grid2[i];
for (int j = 0; j < n; ++j) {
if (grid1[i][j] != grid2[i][j]) {
std::cout << i + 1 << " " << j + 1 << std::endl;
return 0;
}
}
}
return 0;
}
問題C: 石の合体
与えられた数列を処理します。隣り合う同じ数値があれば、それらを合体させます(値をインクリメントし、一つを削除)。この操作を繰り返し、最終的な数列の長さを出力します。
コード例
#include <iostream>
#include <vector>
int main() {
int n;
std::cin >> n;
std::vector<int> stones;
int count;
while (n--) {
std::cin >> count;
stones.push_back(count);
// 合体可能な限りループ
while (stones.size() > 1 && stones.back() == stones[stones.size() - 2]) {
stones[stones.size() - 2]++;
stones.pop_back();
}
}
std::cout << stones.size() << std::endl;
return 0;
}
問題D: 塗りつぶしと境界
グリッド上の'.'の連結成分をBFSで探索します。各連結成分について、その中のセル数と、'#'に隣接する境界セルの数を数えます。セル数と境界セル数の和が最大のものを求めます。
コード例
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
int main() {
int rows, cols;
std::cin >> rows >> cols;
std::vector grid(rows);
for (int i = 0; i < rows; ++i) {
std::cin >> grid[i];
}
std::vector visited(rows, std::vector<bool>(cols, false));
int max_score = 0;
const int dx[] = {0, 1, -1, 0};
const int dy[] = {1, 0, 0, -1};
auto is_boundary = [&](int x, int y) {
for (int i = 0; i < 4; ++i) {
int nx = x + dx[i];
int ny = y + dy[i];
if (nx >= 0 && nx < rows && ny >= 0 && ny < cols && grid[nx][ny] == '#') {
return true;
}
}
return false;
};
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
if (grid[i][j] == '.' && !visited[i][j]) {
std::queue> q;
q.push({i, j});
visited[i][j] = true;
int cells = 1, boundaries = 0;
while (!q.empty()) {
auto [x, y] = q.front();
q.pop();
if (is_boundary(x, y)) {
boundaries++;
}
for (int k = 0; k < 4; ++k) {
int nx = x + dx[k];
int ny = y + dy[k];
if (nx >= 0 && nx < rows && ny >= 0 && ny < cols && grid[nx][ny] == '.' && !visited[nx][ny]) {
visited[nx][ny] = true;
q.push({nx, ny});
cells++;
}
}
}
max_score = std::max(max_score, cells + boundaries);
}
}
}
std::cout << max_score << std::endl;
return 0;
}
問題E: 座標変換と距離和
座標を45度回転し、曼哈頓距離の半分を計算します。座標を(x+y, x-y)に変換することで、4方向への移動は(x±2, y)や(x, y±2)になります。点の偶奇性(変換後のx+yの偶奇)でグループ分けし、各グループ内の点間距離和を前処理和を用いて効率的に計算します。
コード例
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
int n;
std::cin >> n;
std::vector<int> x_coords_odd, y_coords_odd, x_coords_even, y_coords_even;
for (int i = 0; i < n; ++i) {
int x, y;
std::cin >> x >> y;
int transformed_x = x + y;
int transformed_y = x - y;
if (transformed_x % 2 == 0) {
x_coords_even.push_back(transformed_x);
y_coords_even.push_back(transformed_y);
} else {
x_coords_odd.push_back(transformed_x);
y_coords_odd.push_back(transformed_y);
}
}
// 前処理和を計算するヘルパー関数
auto calculate_sum = [](std::vector<int>& coords) {
std::sort(coords.begin(), coords.end());
long long total_distance = 0;
long long prefix_sum = 0;
for (int i = 0; i < coords.size(); ++i) {
total_distance += (long long)i * coords[i] - prefix_sum;
prefix_sum += coords[i];
}
return total_distance;
};
long long answer = calculate_sum(x_coords_odd) + calculate_sum(y_coords_odd) +
calculate_sum(x_coords_even) + calculate_sum(y_coords_even);
std::cout << answer / 2 << std::endl;
return 0;
}