The 14th Blue Bridge Cup (Phase 3) Simulation Competition テスト問題と解答 C++
質問A
【問題解説】
16 進数に変換すると、すべての数字 (先頭の 0 を除く) が文字 (A から F) になる、2022 より大きい最小の数字を見つけてください。
この数値の 10 進形式を回答として送信してください。
【回答提出】
これは空欄に結果を記入する問題です。結果を計算して提出するだけです。この質問の結果は整数です。回答を送信するときにのみこの整数を入力してください。冗長な内容を入力すると、スコアが発生しません。
問題解決:塩基変換
剰余と除算を継続的に使用して、16 進数に変換した後の各桁が > 9 であるかどうかを判断します。
出力をフォーマットするとき、%x プレースホルダーは整数を 16 進数の出力に変換できます。うまくいかない場合は、再度出力して、目で見つけることができます。
// 答案:2730
#include <bits/stdc++.h>
using namespace std;
bool check(int x) {
while (x) {
if (x % 16 <= 9) return false;
x /= 16;
}
return true;
}
int main() {
int ans = 2023;
while (!check(ans)) {
printf("%d --> %x\n", ans, ans);
ans ++;
}
printf("%d --> %x\n", ans, ans);
cout << ans << endl;
return 0;
}
質問B
【問題解説】
Excel では、列名に英字の組み合わせが使用されます。最初の 26 列は A から Z までの順序で 1 つの文字を使用し、次の 26*26 列は AA から ZZ までの順序で 2 つの文字の組み合わせを使用します。
列 2022 の名前は?
【回答提出】
これは空欄に結果を記入する問題です。結果を計算して提出するだけです。この質問の結果は大文字で構成された文字列です. 回答を提出するときはこの文字列のみを記入してください. 余分な内容を記入するとポイントを獲得できません.
問題解決: キャリーをシミュレートする
配列を使用して各ビットをシミュレートします。キャリーは 26 キャリーと等しくありませんが、26 キャリーよりも大きく、現在のビットから 26 を減算します。
// 答案:byt
#include <bits/stdc++.h>
using namespace std;
int a[10];
void output() {
for (int i = 9; i >= 0; i --) {
if (a[i])
cout << char(a[i] - 1 + 'A');
}
cout << endl;
}
int main() {
for (int i = 1; i <= 2022; i ++) {
a[0] ++;
for (int i = 0; a[i]; i ++) {
while (a[i] > 26) {
a[i] -= 26;
a[i + 1] ++;
}
}
cout << i << " --> ";
output();
}
cout << endl;
return 0;
}
質問C
【問題解説】
日付の場合、年の桁の合計、または月と日の桁の合計を計算できます。1900 年 1 月 1 日から 9999 年 12 月 31 日までの合計日数は何日ですか? 年の桁の合計は、月の桁の合計と日の桁の合計に等しくなります。
たとえば、2022 年 11 月 13 日は、2+0+2+2=(1+1)+(1+3) であるため、要件を満たします。
基準を満たす日付の総数を送信してください。
【回答提出】
これは空欄に結果を記入する問題です。結果を計算して提出するだけです。この質問の結果は整数です。回答を送信するときにのみこの整数を入力してください。冗長な内容を入力すると、スコアが発生しません。
解決策: 日付シミュレーション
// 答案:70910
#include <bits/stdc++.h>
using namespace std;
int sum_num(int x) {
int sum = 0;
while (x) {
sum += (x % 10);
x /= 10;
}
return sum;
}
bool check(int y) {
return y % 4 == 0 && y % 100 != 0 || y % 400 == 0;
}
int days[13] = {
0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int yy = 1900, MM = 1, dd = 1;
int main() {
int ans= 0;
while (yy < 10000) {
int a = sum_num(yy);
int b = sum_num(MM) + sum_num(dd);
if (a == b) {
ans ++;
}
bool flag = (MM == 2 && check(yy));
if (flag) days[2] ++;
dd ++;
if (dd > days[MM]) {
dd = 1;
MM ++;
if (MM > 12) {
MM = 1;
yy ++;
}
}
if (flag) days[2] --;
}
cout << ans << endl;
return 0;
}
質問 D
【問題解説】
Xiaolan には 30 の数字があります。つまり、99、22、51、63、72、61、20、88、40、21、63、30、11、18、99、12、93、16、7、53、64、9 です。 、28、84、34、96、52、82、51、77。
Xiaolan は、これらの番号からシリアル番号が異なる 2 つの番号を取ることができ、30*29/2=435 の方法でそれらを取ることができます。
これらの 435 のメソッドのうち、2022 以上の 2 つの数値の積を生成するメソッドはいくつあるかお尋ねしてもよろしいですか?
【回答提出】
これは空欄に結果を記入する問題です。結果を計算して提出するだけです。この質問の結果は整数です。回答を送信するときにのみこの整数を入力してください。冗長な内容を入力すると、スコアが発生しません。
問題の解決策: 暴力のサイクル
// 答案:189
#include <bits/stdc++.h>
#include <cstdio>
using namespace std;
int a[30];
int main() {
for (int i = 0; i < 30; i ++) {
cin >> a[i];
getchar();
}
for (int i = 0; i < 30; i ++) {
cout << a[i] << " ";
}
cout << "\n";
int ans = 0;
int cnt = 0;
for (int i = 0; i < 30; i ++) {
for (int j = i + 1; j < 30; j ++) {
if (a[i] * a[j] >= 2022) {
cout << a[i] << " * " << a[j] << " = " << a[i] * a[j] << "\n";
ans ++;
}
cnt ++;
}
}
cout << "cnt = " << cnt << endl;
cout << ans << endl;
return 0;
}
質問 E
【問題解説】
Xiaolan には 30 行 60 列の数値の行列があり、行列の各数値は 0 または 1 です。
110010000011111110101001001001101010111011011011101001111110
010000000001010001101100000010010110001111100010101100011110
001011101000100011111111111010000010010101010111001000010100
101100001101011101101011011001000110111111010000000110110000
010101100100010000111000100111100110001110111101010011001011
010011011010011110111101111001001001010111110001101000100011
101001011000110100001101011000000110110110100100110111101011
101111000000101000111001100010110000100110001001000101011001
001110111010001011110000001111100001010101001110011010101110
001010101000110001011111001010111111100110000011011111101010
011111100011001110100101001011110011000101011000100111001011
011010001101011110011011111010111110010100101000110111010110
001110000111100100101110001011101010001100010111110111011011
111100001000001100010110101100111001001111100100110000001101
001110010000000111011110000011000010101000111000000110101101
100100011101011111001101001010011111110010111101000010000111
110010100110101100001101111101010011000110101100000110001010
110101101100001110000100010001001010100010110100100001000011
100100000100001101010101001101000101101000000101111110001010
101101011010101000111110110000110100000010011111111100110010
101111000100000100011000010001011111001010010001010110001010
001010001110101010000100010011101001010101101101010111100101
001111110000101100010111111100000100101010000001011101100001
101011110010000010010110000100001010011111100011011000110010
011110010100011101100101111101000001011100001011010001110011
000101000101000010010010110111000010101111001101100110011100
100011100110011111000110011001111100001110110111001001000111
111011000110001000110111011001011110010010010110101000011111
011110011110110110011011001011010000100100101010110000010011
010011110011100101010101111010001001001111101111101110011101
1 とマークされた 1 つの場所から 1 とマークされた別の場所まで、上下左右に歩くことができる場合、2 つの場所は接続されていると言われます。1 とマークされた場所に接続されているすべての場所 (それ自体を含む) は、接続されたブロックを形成します。
マトリックス内の最大の連結ブロックの大きさは?
【回答提出】
これは空欄に結果を記入する問題です。結果を計算して提出するだけです。この質問の結果は整数です。回答を送信するときにのみこの整数を入力してください。冗長な内容を入力すると、スコアが発生しません。
ソリューション: Guangsou
// 答案:148
#include <bits/stdc++.h>
using namespace std;
int m = 30, n = 60;
char mat[35][65];
int ans = 0;
int dx[4] = {
1, 0, -1, 0};
int dy[4] = {
0, 1, 0, -1};
int get_cnt(int i, int j) {
queue<int> q;
q.push(i * 100 + j);
mat[i][j] = '0';
int cnt = 0;
while (q.size()) {
int x = q.front();
q.pop();
i = x / 100;
j = x % 100;
cnt ++;
for (int k = 0; k < 4; k ++) {
int x = i + dx[k];
int y = j + dy[k];
if (x < 0 || x >= m || y < 0 || y >= n || mat[x][y] != '1') {
continue;
}
mat[x][y] = '0';
q.push(x * 100 + y);
}
}
return cnt;
}
int main() {
for (int i = 0; i < m; i ++) {
cin >> mat[i];
}
for (int i = 0; i < m; i ++) {
for (int j = 0; j < n; j ++) {
if (mat[i][j] == '1') {
ans = max(ans, get_cnt(i, j));
}
}
}
cout << ans << endl;
return 0;
}
質問 F
【問題解説】
ある日が何曜日であるかを考えると、n 日後には何曜日になりますか?
【入力フォーマット】
入力の最初の行には整数 w が含まれており、指定された日が何曜日であるかを示します。w は月曜日から土曜日までの 1 から 6 であり、日曜日は w 7 です。
2 行目には整数 n が含まれています。
【出力フォーマット】
出力の 1 行には n 日後の曜日を示す整数が含まれ、1 から 6 は月曜日から土曜日を表し、7 は日曜日を表します。
【入力例】
6
10
【出力例】
2
【評価ユースケースの規模と合意】
すべての評価ケースで 1 <= n <= 1000000。
問題の解決策: 残りを取る
#include <bits/stdc++.h>
using namespace std;
int w, n;
int main() {
cin >> w >> n;
w = (w + n) % 7;
if (w == 0) w = 7;
cout << w << endl;
return 0;
}
質問G
【問題解説】
Xiaolanは、エリア内の信号塔の設置を担当しています.エリア全体は長方形のエリアです.座標軸が確立された後、南西隅の座標は(0, 0)、南東隅の座標は(W ,0)であり、北西隅の座標は(0,H)であり、北東隅の座標は(W,H)である。ここで、W、H は整数です。
彼は信号塔を n か所に設置し、各信号塔は自身を中心とする半径 R (エッジを含む) の円をカバーできます。
信号の範囲を確認するために、Xiaolan は、水平座標と垂直座標が整数である領域内のすべてのポイントをテストして、信号の状態を確認することを計画しています。横座標は 0 ~ W、縦座標は 0 ~ H の範囲で、合計 (W+1) * (H+1) 点がテストされます。
信号塔の位置が与えられると、これらの (W+1)*(H+1) ポイントのうちいくつが信号によってカバーされるか。
【入力フォーマット】
入力の最初の行には、隣接する整数間のスペースで区切られた 4 つの整数 W、H、n、R が含まれます。
次の n 行では、各行にシグナル タワーの座標を表す 2 つの整数 x、y が含まれます。信号塔が重なっている場合があります。これは、2 つの信号送信機が同じ場所に設置されていることを示しています。
【出力フォーマット】
出力行には、答えを表す整数が含まれます。
【入力例】
10 10 2 5
0 0
7 0
【出力例】
57
【評価ユースケースの規模と合意】
すべての評価ケースで、1 <= W、H <= 100、1 <= n <= 100、1 <= R <= 100、0 <= x <= W、0 <= y <= H。
問題解決: 暴力的なシミュレーション
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 105;
int mat[N][N];
int w, h, n, r;
int a[N][2];
signed main() {
cin >> w >> h >> n >> r;
for (int i = 0; i < n; i ++) {
cin >> a[i][0] >> a[i][1];
}
int rr = r * r;
int ans = 0;
for (int i = 0; i <= w; i ++) {
for (int j = 0; j <= h; j ++) {
for (int k = 0; k < n; k ++) {
int x = (i - a[k][0]) * (i - a[k][0]) + (j - a[k][1]) * (j - a[k][1]);
if (x <= rr) {
ans ++;
break;
}
}
}
}
cout << ans << endl;
return 0;
}
質問H
【問題解説】
Xiaolanにはn * mサイズの長方形の水域があり、Xiaolanはこの水域をn行m列に分割し、行数は1からn、列数は1からmです。各行と各列の幅は単位 1 です。
現在、この水域は水生植物でいっぱいで、シャオランは水生植物をきれいにしたいと考えています。
毎回、Xiaolan は、列 c1 (含む) から行 r1 (含む) の列 c2 (含む) から行 r2 (含む) までの四角形の領域をクリーンアップできます。
一定期間清掃した後、清掃されていない場所がいくつあるか尋ねます。
【入力フォーマット】
入力の最初の行には、スペースで区切られた 2 つの整数 n、m が含まれます。
2 行目には、クリーンアップの回数を表す整数 t が含まれています。
次の t 行では、各行に 4 つの整数 r1、c1、r2、c2 が含まれます。隣接する整数はスペースで区切られ、クリーンアップを示します。エントリの順序に注意してください。
【出力フォーマット】
出力行には、クリーニングされていない領域を表す整数が含まれています。
【入力例】
2 3
2
1 1 1 3
1 2 2 2
【出力例】
2
【入力例】
30 20
2
5 5 10 15
6 7 15 9
【出力例】
519
【評価ユースケースの規模と合意】
すべての評価ケースで、1 <= r1 <= r2 <= n <= 100、1 <= c1 <= c2 <= m <= 100、0 <= t <= 100。
問題の解決策: 暴力のサイクル
#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int a[N][N];
int m, n;
int t;
int r1, c1, r2, c2;
int main() {
cin >> m >> n;
cin >> t;
while (t --) {
cin >> r1 >> c1 >> r2 >> c2;
for (int i = r1; i <= r2; i ++) {
for (int j = c1; j <= c2; j ++) {
a[i][j] = 1;
}
}
}
int ans = 0;
for (int i = 1; i <= m; i ++) {
for (int j = 1; j <= n; j ++) {
ans += (a[i][j] == 0);
}
}
cout << ans << endl;
return 0;
}
質問Ⅰ
【問題解説】
Xiaolanはオープンフィールドでスライドします.フィールドの高さは異なります.Xiaolanはn行m列のマトリックスを使用してフィールドを表し、マトリックス内の値はフィールドの高さを表します.
Xiaolan が特定の位置にいて、上下左右のいずれかの位置の高さが現在の高さより (厳密に) 低い場合、Xiaolan はそこにスライドでき、スライド距離は 1 です。
Xiaolan が特定の位置にいて、上下左右のすべての位置の高さが現在の高さ以上である場合、Xiaolan のスケートは終了します。
Xiaolan は、マトリックスによって表されるフィールドから滑り出すことはできません。
Xiaolan は滑空を開始する位置を自由に選択できます。
【入力フォーマット】
入力の最初の行には、スペースで区切られた 2 つの整数 n、m が含まれます。
次の n 行には、各行に m 個の整数が含まれ、隣接する整数間のスペースで区切られ、各位置の高さを順番に示します。
【出力フォーマット】
出力行には、答えを表す整数が含まれます。
【入力例】
4 5
1 4 6 3 1
11 8 7 3 1
9 4 5 2 1
1 3 2 2 1
【出力例】
7
【記載例】
スライド位置は(2,1)、(2,2)、(2,3)、(3,3)、(3,2)、(4,2)、(4,3)の順です。
【評価ユースケースの規模と合意】
評価ケースの 30% では、1 <= n <= 20、1 <= m <= 20、0 <= 高さ <= 100 です。
すべての評価ケースで、1 <= n <= 100、1 <= m <= 100、0 <= 高さ <= 10000。
解決策:メモリ検索
#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int a[N][N];
int mp[N][N];
int m, n;
int dx[4] = {
1, 0, -1, 0};
int dy[4] = {
0, -1, 0, 1};
int dfs(int i, int j) {
if (mp[i][j] != -1) return mp[i][j];
int ret = 0;
for (int k = 0; k < 4; k ++) {
int x = i + dx[k];
int y = j + dy[k];
if (x < 0 || x >= m || y < 0 || y >= n || a[x][y] >= a[i][j]) {
continue;
}
ret = max(ret, dfs(x, y) + 1);
}
return mp[i][j] = ret;
}
int main() {
memset(mp, -1, sizeof(mp));
cin >> m >> n;
for (int i = 0; i < m; i ++) {
for (int j = 0; j < n; j ++) {
cin >> a[i][j];
}
}
int ans = 0;
for (int i = 0; i < m; i ++) {
for (int j = 0; j < n; j ++) {
ans = max(ans, dfs(i, j));
}
}
cout << ans + 1 << endl;
return 0;
}
質問 J
【問題解説】
Xiaolan には、シーケンス a[1]、a[2]、...、a[n] があります。
正の整数 k が与えられたとき、1 から n までの各通し番号 i について、2k+1 個の数のうち a[ik]、a[i-k+1]、…、a[i+k] の数は何ですか?最小値ですか?添字が 1 から n の範囲を超える場合、その数は存在せず、存在する値のみが最小値の計算に使用されます。
【入力フォーマット】
入力の最初の行には、整数 n が含まれています。
2 行目には、それぞれ a[1]、a[2]、…、a[n] を表す n 個の整数が含まれています。
3 行目には整数 k が含まれています。
【出力フォーマット】
n 個の整数を含む 1 行を出力し、それぞれのシーケンス番号で得られた最小値を表します。
【入力例】
5
5 2 7 4 3
1
【出力例】
2 2 2 3 3
【評価ユースケースの規模と合意】
評価ケースの 30% では、1 <= n <= 1000、1 <= a[i] <= 1000 です。
評価ケースの 50% では、1 <= n <= 10000、1 <= a[i] <= 10000 です。
すべての評価ケースで、1 <= n <= 1000000、1 <= a[i] <= 1000000。
解決策: モノトニック キュー
STL に慣れている場合は、map を使用して各数値の出現回数を記録し、追加と削除を制御し、マップの最初のキーを答えとして出力することができます。
#include <bits/stdc++.h>
using namespace std;
const int N = 1E6 + 5;
int a[N];
int x;
int n, k;
int main() {
deque<int> dq;
cin >> n;
for (int i = 1; i <= n; i ++) {
cin >> a[i];
}
cin >> k;
for (int i = 1; i <= n + k; i ++) {
if (i <= n) {
// 右端点在数轴上
x = a[i];
while (dq.size() && dq.back() > x) {
dq.pop_back();
}
dq.push_back(x);
}
if (i - k - k > 1) {
// 左端点超过 1
x = a[i - k - k - 1];
if (dq.front() == x) {
dq.pop_front();
}
}
if (i - k > 0) {
// 中点在数轴上
cout << dq.front();
if (i != n + k) cout << " ";
}
}
cout << endl;
return 0;
}