問題A:数値間隔の算出
入力値 $R$ が属する百の位区間を特定し、その区間の上限値との差分を出力する問題です。条件分岐を用いる代わりに、整数除算による切り上げ演算の特性を活用することで、簡潔な式に変換可能です。
#include <iostream>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int current_rating;
if (!(cin >> current_rating)) return 0;
int next_hundred = ((current_rating + 99) / 100) * 100;
cout << (next_hundred - current_rating) << '\n';
return 0;
}
問題B:順位ベースの閾値評価
与えられた数列を昇順に整列させ、下から $P$ 番目の要素を取得します。取得した値が目標スコア $T$ に満たない場合、その不足分を計算し、既に達成している場合は $0$ を返します。インデックスのオフセット計算に注意が必要です。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, target_val, rank;
cin >> n >> target_val >> rank;
vector<int> data(n);
for (int &x : data) cin >> x;
sort(data.begin(), data.end());
int reference = data[n - rank];
cout << max(0, target_val - reference) << '\n';
return 0;
}
問題C:順列生成と部分回文の除外
文字列の全順列を生成し、各配置に対して長さ $K$ の連続部分列が回文構造を持つかを検証します。`next_permutation` による辞書順走査を行い、スライディングウィンドウ形式で中央一致判定を実行します。回文が存在しないパターン数を累積します。
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
bool contains_palindrome(const string& s, int len) {
for (size_t i = 0; i <= s.size() - len; ++i) {
bool match = true;
for (int offset = 0; offset < len / 2; ++offset) {
if (s[i + offset] != s[i + len - 1 - offset]) {
match = false;
break;
}
}
if (match) return true;
}
return false;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, k;
cin >> n >> k;
string base;
cin >> base;
sort(base.begin(), base.end());
int valid_count = 0;
do {
if (!contains_palindrome(base, k)) {
++valid_count;
}
} while (next_permutation(base.begin(), base.end()));
cout << valid_count << '\n';
return 0;
}
問題D:構成ベースの回文数探索
回文数は桁数に応じて規則的に増加します(例:1桁9個、2桁9個、3桁90個…)。対象の $N$ がどの桁数群に属するかを算出し、前半分の桁を数値生成します。生成した前半を鏡像化して結合する際、奇数桁か偶数桁かに応じて中央文字の重複を調整します。$N=1$ の場合は $0$ を特別扱いします。
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
long long n;
cin >> n;
if (n == 1) {
cout << "0\n";
return 0;
}
--n;
long long block_size = 9;
while (n >= block_size * 2) {
n -= block_size * 2;
block_size *= 10;
}
--n;
string prefix = to_string(n % block_size + block_size / 9);
string suffix = prefix;
reverse(suffix.begin(), suffix.end());
if (n < block_size) {
prefix.pop_back();
}
cout << prefix + suffix << '\n';
return 0;
}
問題E:水位上昇シミュレーション
グリッド内の高地が海面上昇に伴い侵食される過程をシミュレーションします。初期状態で境界に接するセルを最小ヒープに投入し、毎年の水位上昇時にヒープの最小値と比較します。侵食されたセルの隣接マスを未訪問セットから除外し、ヒープに追加することで洪水伝播を効率的に処理します。
#include <iostream>
#include <vector>
#include <queue>
#include <set>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int h, w, max_year;
cin >> h >> w >> max_year;
vector<vector<int>> terrain(h + 2, vector<int>(w + 2));
priority_queue<pair<int, pair<int, int>>,
vector<pair<int, pair<int, int>>>,
greater<>> pq;
set<pair<int, int>> inland;
for (int r = 1; r <= h; ++r) {
for (int c = 1; c <= w; ++c) {
cin >> terrain[r][c];
bool is_edge = (r == 1 || r == h || c == 1 || c == w);
if (is_edge) {
pq.push({terrain[r][c], {r, c}});
} else {
inland.insert({r, c});
}
}
}
const int dr[] = {0, 0, 1, -1};
const int dc[] = {1, -1, 0, 0};
int remaining = h * w;
for (int year = 1; year <= max_year; ++year) {
while (!pq.empty()) {
auto [height, pos] = pq.top();
auto [cur_r, cur_c] = pos;
if (height > year) break;
pq.pop();
--remaining;
for (int k = 0; k < 4; ++k) {
int nr = cur_r + dr[k];
int nc = cur_c + dc[k];
if (nr >= 1 && nr <= h && nc >= 1 && nc <= w) {
if (inland.erase({nr, nc})) {
pq.push({terrain[nr][nc], {nr, nc}});
}
}
}
}
cout << remaining << '\n';
}
return 0;
}