序文:
これは、Blue Bridge シミュレーション コンペティションの最初のブログ記録です。多くの至らない点があるかもしれません。ここで、第 15 回 Blue Bridge Cup シミュレーション コンペティションのグループ B (第 2 回) の問題とコードを共有します。私は C++ を使用しました。アルゴリズムに関するいくつかの質問は、私がそれらを行っているときに混乱したため、アドバイスを得るために他の専門家とそれらのいくつかを共有しました。
目次
1. 質問A
問題の説明
Xiaolan は、各単語が同じ幅のテキスト行を画面上に配置したいと考えています。
Xiaolan は、各文字の幅が 36 ピクセルの場合、1 行にちょうど 30 文字を、文字の間や前後に隙間なく配置できることを発見しました。
各文字の幅が 10 ピクセルで、文字間に隙間がない場合、1 行に何文字まで配置できますか。
言うことはあまりありません。これは単なる小学校の算数の問題です。36 × 30 / 10 = 108
答え: 108
二、试题B
問題の説明
2^2023%1000 を求めます。これは、2 の 2023 乗を 1000 で割った余りです。
%1000 には 2^2023 の下 3 桁が必要です。これは単なる穴埋め問題なので、電卓を使用して直接計算できます。
答え: 608
3. 質問C
問題の説明
2 進数に変換された正の整数と 8 進数に変換された正の整数のすべての桁の合計が等しい場合、その桁の合計が等しい数値と呼ばれます。
最初の数桁の合計が同じである正の整数は、1、8、9、64、... です。
23 桁目の和が等しい正の整数は何ですか?
ブルートフォースまたはプログラミングを使用して問題を解決できます
#include<bits/stdc++.h>
#define num first
#define y second
using namespace std;
typedef long long ll;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
// 十进制数转换为任意n进制数
// num:十进制数,n:转换成n进制数
string Itoa(int num,int n)
{
string str;
int rem;
char ch;
if(num == 0)
str = "0";
while(num > 0)
{
rem = num % n;
ch = (rem < 10) ? (rem + '0') : (rem - 10 + 'A');
str = ch + str;
num /= n;
}
return str;
}
// 计算每一位上的和
int sum(string str)
{
int sum = 0;
for(int i = 0;i < str.length();i ++)
{
sum += str[i] - '0';
}
return sum;
}
string str1;
string str2;
int main()
{
int cnt = 0;
int i = 1;
while(1)
{
str1 = Itoa(i,2);
str2 = Itoa(i,8);
// cout<<i<<' '<<str1<<' '<<str2<<endl;
if(sum(str1) == sum(str2))
{
cnt ++;
cout << "数字为" << i << endl;
cout << str1 << endl;
cout << str2 << endl;
cout << "cnt的值是" << cnt << endl;
}
if(cnt == 23)
{
cout << "找到了!!!:>" << i << endl;
cout << str1 << endl;
cout << str2 << endl;
break;
}
i ++;
}
return 0;
}
番号は 1 です 1 1 cntの値は1です 数字は8です 1000 10 cntの値は2です 数字は9です 1001 11 cntの値は3です その数は64です 1000000 100 cntの値は4です その数は65です 1000001 101 cntの値は5です その数は72です 1001000 110 cntの値は6です その数は73です 1001001 111 cntの値は7です その数は512です 1000000000 1000 cntの値は8です その数は513です 1000000001 1001 cntの値は9です その数は520です 1000001000 1010 cntの値は10です その数は521です 1000001001 1011 cntの値は11です その数は576です 1001000000 1100 cntの値は12です その数は577です 1001000001 1101 cntの値は13です その数は584です 1001001000 1110 cntの値は14です その数は585です 1001001001 1111 cntの値は15です 番号は4096です 1000000000000 10000 cntの値は16です 番号は4097です 1000000000001 10001 cntの値は17です 番号は4104です 1000000001000 10010 cntの値は18です 番号は4105です 1000000001001 10011 cntの値は19です 番号は4160です 1000001000000 10100 cntの値は20です 番号は4161です 1000001000001 10101 cntの値は21です 番号は4168です 1000001001000 10110 cntの値は22です 番号は4169です 1000001001001 10111 cntの値は23です 見つけました!!!:>4169 1000001001001 10111
答え: 4169
四、试题D
問題の説明
次の数値 (6 行、各行に 6 個、合計 36 個) について、約数の数が最も大きいものはどれですか? (複数ある場合は一番早いものをご回答ください)
393353 901440 123481 850930 423154 240461
373746 232926 396677 486579 744860 468782
941389 777714 992588 343292 385198 876426
483857 241899 544851 647930 772403 109929
882745 372491 877710 340000 659788 658675
296521 491295 609764 718967 842000 670302
おおよその数値のテンプレートの質問
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int primes[N], cnt;
bool st[N];
void init(int n)
{
for (int i = 2; i <= n; i ++)
{
if (!st[i]) primes[cnt ++] = i;
for (int j = 0; primes[j] * i <= n; j ++)
{
st[primes[j] * i] = true;
if (i % primes[j] == 0) break;
}
}
}
void divide(int x)
{
int res = 0;
for (int i = 0; i < cnt; i ++)
{
int p = primes[i];
if (x % p == 0)
{
while (x % p == 0)
{
res ++;
{
x /= p;
}
}
}
}
cout << res << endl;
}
int main()
{
init(N);
int m = 30;
while (m--)
{
int x;
cin >> x;
divide(x);
}
return 0;
}
答え: 901440
五、试题E
問題の説明
Xiaolan には 01 マトリックスがあります。彼は、最初の行と最初の列の 0 を 2 に変更するつもりです。変化のプロセスは伝染し、上下左右の隣接する4つの位置に2が入るたびに0が2になります。最終的には 2 がすべて 1 または 2 に囲まれるまでです。すみません、最終的な行列には 2 がいくつありますか?
以下は Xiaolan の行列で、合計 30 行 40 列あります。 00001000100000011010101001001100000011 0101111001111101110111100000101010011111 10100 0110101010110000000101100100000101001 001 010100011 0100110010000110000000100010000101110000 1001011101101 0011110100011000000001101001101110100001 010001110111011 00 0010110000001000001010100011000010100011 000101100000000000010 0011001000001000000010011001100101000110 000110100100000101 0010001 0100010010000110100001100000110111110101 00101000000111100110010101101 | 0010110101001100000100000010000010110011 | 100 100000011000101011000000010101 1001111010010110011010101110000000101110 1000000010010011001000100110010000101 100110001010001 0000100000101111111111100 0011000100011000010111101000101110110001
Classic BFS (breadth first search) は接続されたブロックを検索しますが、質問の意味から、接続されているブロック内のすべて 0 の 0 の数が必要であることがわかります。
#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 45;
char g[N][N];
bool st[N][N];
int dx[4] = {1, 0, -1, 0}, dy[4] = {0, -1, 0, 1};
int ans;
void bfs(int x, int y)
{
queue<PII> q;
st[x][y] = true;
q.push({x, y});
ans++;
while (q.size())
{
auto t = q.front();
q.pop();
for (int i = 0; i < 4; i++)
{
int a = dx[i] + t.x, b = dy[i] + t.y;
if (a < 0 || a >= 30 || b < 0 || b >= 40) continue;
if (st[a][b]) continue;
if (g[a][b] != '0') continue;
ans++;
st[a][b] = true;
q.push({a, b});
}
}
}
int main()
{
for (int i = 0; i < 30; i++) cin >> g[i];
bfs(0, 0);
cout << ans << endl;
return 0;
}
答え: 541
六、试题F
問題の説明
正確に 6 桁の正の整数 x が与えられた場合、x を左に 1 ビット回転して出力してください。
いわゆる 1 桁の左への循環シフトは、元の 100,000 桁が一の桁に変更され、元の 10,000 桁が左に移動されて 100,000 桁が十の桁になることを意味します。
例: 194910 は 1 桁左にシフトされ、949101 になります。
別の例: 987123 は 1 つ左にシフトされて 871239 になります。
入力フォーマット
整数 x を含む行を入力します。入力 x に 10 進数が 6 桁正確に含まれていること、および数十万桁および数万桁の数値が 0 ではないことを確認してください。
出力フォーマット
出力行には、答えを表す整数が含まれます。サンプル入力 194910 サンプル出力 949101
直接文字列、簡単なシミュレーションで十分ですが、この問題は点を取るための古典的な問題としか言いようがありません。
#include <bits/stdc++.h>
using namespace std;
int main()
{
string s;
cin >> s;
for(int i = 1; i < s.size(); i ++)
cout << s[i];
cout << s[1];
return 0;
}
7. 質問G
問題の説明
英小文字のみを含む文字列を入力してください。この文字列の最後の母音は何ですか?
英語では、a、e、i、o、uの合計5文字が母音で、その他の文字は母音ではありません。
入力フォーマット
英語の小文字のみで構成され、その文字列に少なくとも 1 つの母音が含まれる文字列を含む行を入力します
出力フォーマット
出力には、答えを表す 1 文字が含まれます。
サンプル入力
蘭橋
サンプル出力
○
サンプル入力
カップ
サンプル出力
で
この質問は、前の質問とほぼ同じ難易度です。文字列をループし、最初の母音を後ろから前に出力する単純なシミュレーションです。
#include <bits/stdc++.h>
using namespace std;
int main()
{
string s;
cin >> s;
for(int i = s.size() - 1; i >= 0; i--)
{
if(s[i] == 'a' || s[i] == 'o' || s[i] == 'e' || s[i] == 'i' || s[i] == 'u')
{
cout << s[i] << endl;
break;
}
}
return 0;
}
8. テスト問題 H
問題の説明
整数を指定すると、その整数の変換は、整数のすべての桁のゼロ以外の桁の積になります。
たとえば、123456789 は 123456789=362880 に一度変換され、36288=2304 に再変換され、234=24 に再変換され、8 に再変換されます。
整数が与えられた場合、変換プロセスで各整数のエクスペリエンスを 10 未満になるまで順番に出力してください。
入力フォーマット
整数 n を含む行を入力します。
出力フォーマット
複数行を出力します。各行には整数が含まれます。
サンプル入力
123456789
サンプル出力
362880
2304
24
8
評価ユースケースの規模と規約
評価ケースの 50% では、1 <= n <= 10^9 (10 の 9 乗) になります。
すべての評価ケースで、1 <= n <= 10^18 (10 の 18 乗)。
単純にシミュレーションする
#include <bits/stdc++.h>
using namespace std;
int main()
{
long long int n;
cin >> n;
long long int sum = 11;
while(sum >= 10)
{
sum = 1;
while(n)
{
if((n % 10) != 0)
sum *= n % 10;
n /= 10;
}
cout << sum << " "<< endl;
n = sum;
}
return 0;
}
9. テスト問題 I
問題の説明
Xiaolan は n 行 m 列の正方形の図の中央に立っており、正方形の図の各正方形には正の整数がマークされています。隣接する2つのマス目(4方向に隣接するマス目)の数字の最大公約数が1より大きい場合、一方のマス目からもう一方のマス目へ移動することができ、もちろん、もう一方のマス目から戻ることもできます。
シャオランが r 行、c 列から開始すると仮定します。シャオランはグリッド内で何マスまで移動できますか?
入力フォーマット
入力の最初の行には、グリッド チャートの行と列の数を示す、スペースで区切られた 2 つの整数 n、m が含まれています。次の n 行は、各行に m 個の正の整数が含まれており、隣接する整数の間にスペースで区切られており、グリッド チャートの行 1 から行 n まで、および各行の列 1 から列 m までの数値を表します。
次の行には、Xiaolan の行番号と列番号を示す、スペースで区切られた 2 つの整数 r と c が含まれています。
出力フォーマット
出力行には、答えを表す整数が含まれます。
サンプル入力
3 4
3 6 5 5
2 4 3 5
7 8 3 8
3 2
出力例 5
評価ユースケースの規模と規約
評価ケースの 50%、1 <= n、m <= 100 では、グリッド チャートの各数値は 10^5 (10 の 5 乗) を超えません。
すべての評価ケース、1 <= n、m <= 1000 で、グリッド チャートの各数値は 10^9 (10 の 9 乗) を超えません。
BFS テンプレートの質問には、最大公約数を見つけるステップが追加されているだけです。
#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 1010;
int g[N][N];
int n, m;
int dx[4] = {1, 0, -1, 0}, dy[4] = {0, -1, 0, 1};
int ans;
bool st[N][N];
int gcd(int a, int b)
{
return b ? gcd(b, a % b) : a;
}
void bfs(int x, int y)
{
queue<PII> q;
st[x][y] = true;
q.push({x, y});
ans++;
while (q.size())
{
auto t = q.front();
q.pop();
for (int i = 0; i < 4; i++)
{
int a = dx[i] + t.x, b = dy[i] + t.y;
if (a < 1 || a > n || b < 1 || b > m) continue;
if (st[a][b]) continue;
if (gcd(g[a][b], g[t.x][t.y]) <= 1) continue;
st[a][b] = true;
ans ++;
q.push({a, b});
}
}
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
cin >> g[i][j];
int x, y;
cin >> x >> y;
bfs(x, y);
cout << ans << endl;
return 0;
}
10. 質問J
問題の説明
シーケンス a[1]、a[2]、…、a[n] と整数 k が与えられた場合、その区間内のすべての数値の合計が最大になるような、ちょうど k の長さの区間を見つけてください。
つまり、1 <= p および p+k-1 <= n となるような整数 p を見つけ、a[p]+a[p+1]+...+a[p+k-1] となります。は最もおおきい 。
入力フォーマット
入力の最初の行には、2 つの整数 n と k が含まれています。
2 行目には、指定されたシーケンスを表す、隣接する整数の間にスペースで区切られた n 個の整数が含まれています。
出力フォーマット
出力行には、最大間隔合計を表す整数が含まれています。合計を出力するだけでよく、計画を出力する必要はありません。サンプル入力
6 3 2 3 9 1 9 5
サンプル出力
19
評価ユースケースの規模と規約
評価ケースの 30% では、1 <= k <= n <= 30、1 <= a[i] <= 100。
評価ケースの 60% では、1 <= k <= n <= 1000、1 <= a[i] <= 10000。
すべての評価ケースで、1 <= k <= n <= 100000、1 <= a[i] <= 1000000。
これは単純なスライディング ウィンドウ、プレフィックス、テンプレートの質問です。注意する必要があるのは、長く長く開くことです。そうしないと範囲を超えます。
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,k;
cin >> n >> k;
long long int s[100000];
for(int i = 1; i <= n; i ++)
{
cin >> s[i];
s[i] += s[i - 1];
}
long long int m;
for(int i = 1; i + k - 1 <= n; i ++)
{
m = max(s[i + k - 1] - s[i - 1],m);
}
cout << m << endl;
return 0;
}