2022年第13回ブルーブリッジカップ州大会C/C++グループB個人問題解決

質問A:9から10進数(数学)

A

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

int main() {
	cout << 2 * pow(9, 0) + 2 * pow(9, 1) + 0 * pow(9, 2) + 2 * pow(9, 3) << endl;
	return 0;
}

回答:1478

質問B:春子日付(言語)

B
現在、多くの論争があり、4、5、14の3種類の回答に分けられます。
テスト中に書いた回答は5でしたが
、より多くのネチズンが4と回答し、BlueBridgeCloud
クラスがゲームが14と言った後の夜(非公式)

要約させてください:

最初の答え:5
質問を見てください。20220123を説明するとき、それはストレートを持っていると言います:123。
したがって、123のストレートしかなく、012はストレートではないと考えることができます。
次に、20221023の説明では、210の逆ストレートを指しますが、ストレートの日付ではないと述べています。したがって、0を含めることができないことがより明確であり、逆の順序はストレートと見なすことができると考えられます。

20220123
20220321
20221123
20221230
20221231

2番目の答え:4
は、012とその逆の順序(210など)がストレートとは見なされないことを意味するため、上記の20220321を削除します。

20220123
20221123
20221230
20221231

3番目の答え:
質問14のストレートは、3桁ではなく、3つの連続した数字です。したがって、012もストレートです。2番目の例20221023から、210の逆の順序は直線ではないことがわかります。
012をカウントする場合、2番目の例では、210の逆順は拒否されます。

20220120
20220121
20220122
20220123
20220124
20220125
20220126
20220127
20220128
20220129
20221012
20221123
20221230
20221231

正解はまだわかりませんが、公式説明を待つしかありません
orz

質問C:ブラッシング統計(シミュレーション)

C1

【サンプル入力】

10 20 99

【出力例】

8

ここに画像の説明を挿入

トラップ:a、b、およびnはlong longに格納する必要があることに注意してください
。試験中に記述されたコード:nはlong longに格納する必要があることのみを考慮し、aおよびbの格納にはlonglongを使用しません。時間が制限を超える可能性があると考えた

#include <iostream>
using namespace std;

int main() {
	int cnt = 1;
	long long n;
	int a, b;
	cin >> a >> b >> n;
	long long sum = 0;
	while (sum < n) {
		if (cnt % 7 == 0 || cnt % 7 == 6) {
			sum += b;
		}
		else {
			sum += a;
		}
		cnt++;
	}
	// 当超出时退出while循环,所以答案需要减一。
	cout << cnt - 1 << endl;
	return 0;
}

試合後のコードの最適化:最初に残りを取り、次にブルートフォースを取ります

#include <iostream>
using namespace std;

int main() {
	long long a, b, n;
	cin >> a >> b >> n;
	int week = 5 * a + 2 * b;
	long long ans = n / week * 7;
	n %= week;
	int sum = 0;
	for (int i = 1; i <= 7 && sum < n; i++) {
		if (i % 7 == 6 || i % 7 == 0) {
			sum += b;
		}
		else {
			sum += a;
		}
		ans++;
	}
	cout << ans << endl;
	return 0;
} 

質問D:低木の剪定(パターンの検索)

D1

【サンプル入力】

3

【出力例】

4
2
4

D2
最初に暴力を使ってルールを見つけ、次にルールに従ってコードを単純化します

// 暴力代码:来回走两次。注意回的时候要把两个边界去掉。

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

const int maxn = 1e4 + 100;
int a[maxn];
int maxHeight[maxn];

int main() {
	int n;
	while (cin >> n) {
		memset(a, 0, sizeof(a));
		memset(maxHeight, 0, sizeof(maxHeight));
		
		// 来回走两次
		for (int today = 0; today < n; today++) {
			for (int i = 0; i < n; i++) {
				a[i]++;
				if (a[i] > maxHeight[i]) {
					maxHeight[i] = a[i];
				}
				if (i == today) {
					a[i] = 0;
				}
			}
		}
		for (int today = n - 2; today > 0; today--) {
			for (int i = 0; i < n; i++) {
				a[i]++;
				if (a[i] > maxHeight[i]) {
					maxHeight[i] = a[i];
				}
				if (i == today) {
					a[i] = 0;
				}
			}
		}
		for (int today = 0; today < n; today++) {
			for (int i = 0; i < n; i++) {
				a[i]++;
				if (a[i] > maxHeight[i]) {
					maxHeight[i] = a[i];
				}
				if (i == today) {
					a[i] = 0;
				}
			}
		}
		for (int today = n - 2; today > 0; today--) {
			for (int i = 0; i < n; i++) {
				a[i]++;
				if (a[i] > maxHeight[i]) {
					maxHeight[i] = a[i];
				}
				if (i == today) {
					a[i] = 0;
				}
			}
		}
		for (int i = 0; i < n; i++) {
			cout << maxHeight[i] << " ";
		}
		cout << endl << endl;
	}
	return 0;
}

結果は次のとおりです。
D2
ルールを見つけることでコードを簡略化できます。

#include <iostream>
using namespace std;

int main() {
	int n;
	cin >> n;
	for (int i = 0; i < n; i++) {
		cout << max(i, n - i - 1) * 2 << endl; 
	}
	return 0;
}

質問E:Xベースの減算(数学)

E1

【サンプル入力】

11
3
10 4 0
3
1 2 0

【出力例】

94

E2
ゲームを1時間見ましたが、質問orzがわかりませんでした...
この質問は非常に抽象的で理解しにくいです。

まず、問題の説明の321が65に変換される方法を説明します。
質問から、1の位は2進数、10の位は小数、100の位は8進数です。
タイトルの最初の行は次のように述べています。基本システムは、桁の桁数を指定します。意味:各桁に2、10に1、10に10、100に1。
最初に結果の合計を定義します=
0①1の桁を見てください。1の桁は1です。次に、1に到達するために一度だけカウントする必要があります。次に、結果に1を加算します。つまり、合計+=
1②を見てください。 10桁:10桁は2です。1桁は2進数であるため、10桁を2にする場合は、00-> 01-> 10->11->20の変換を行う必要があります。10進数に1を加えるたびに、1桁を2回変換する必要があるため、10桁を2にするには、合計2(10桁の値)* 2( 1桁の16進数)を変換する必要があります次に、それを結果に追加します。つまり、合計+ = 2 *
2③百の位を見てください。百の位は3です。十の位の分析によれば、同じです。百の位を3にすることです。 3(百の位)を変換する必要があります。値)* 10(10の底)* 2(1の底)回次に、結果をそれに追加します。つまり、合計+ = 3 * 10 * 2
合計するには:321は合計= 1 + 2 * 2 + 3 * 10 * 2=65に変換されます

公式:
A = ( a[n - 1] * X[n - 2] * X[n - 3] * … * X[0] ) + ( a[n - 2] * X[n - 3] * X[n - 4] * … * X[0] ) + … + a[0]
B = ( b[n - 1] * X[n - 2] * X[n - 3] * … * X[0] ) + ( b[n - 2] * X[n - 3] * X[n - 4] * … * X[0] ) + … + b[0]
A - B = (( a[n - 1] - b[n - 1] ) * X[n - 2] * X[n - 3] * … * X[0] ) + (( a[n - 2] - b[n - 2] ) * X[n - 3] * X[n - 4] * … * X[0] ) + ( a[0] - b[0] )
优化:(秦九韶算法)
设 d[n - 1] = a[n - 1] - b[n - 1]
A - B = ((( d[n - 1] * X[n - 2] + d[n - 2] ) * X[n - 3] + d[n - 3] ) * X[n - 4] + … d[0] ) …

コード:

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

const int MOD = 1e9 + 7;
const int maxn = 1e5 + 100;
int a[maxn];
int b[maxn];

int main() {
	int n, m1, m2, m;
	scanf("%d", &n);
	scanf("%d", &m1);
	// 逆序来存,确保让个位对齐,多余位置的值都是 0 
	for (int i = m1 - 1; i >= 0; i--) {
		scanf("%d", &a[i]);
	}
	scanf("%d", &m2);
	for (int i = m2 - 1; i >= 0; i--) {
		scanf("%d", &b[i]);
	}
	m = max(m1, m2);
	int res = 0;
	for (int i = m - 1; i >= 0; i--) {
		res = (res * max({ 2, a[i] + 1, b[i] + 1 }) % MOD + a[i] - b[i]) % MOD;
	}
	printf("%d\n", res);
	return 0;
}

質問F:統計的部分行列(プレフィックス合計+ダブルポインター)

F1

【サンプル入力】

3 4 10
1 2 3 4
5 6 7 8
9 10 11 12

【出力例】

19

F2
F3
kがintの範囲を超えていることに注意してください(到達できませんが、すでにタイムアウトしていますが、注意が必要です)間違って読んだ場合、kの値は2.5 * 10 ^ 8であり、 intの範囲は-2147483648〜21 4748 3647(21 * 10 ^ 8)

方法①:プレフィックス合計+ダブルポインタ
最初に各列のプレフィックス合計を見つけ、次にダブルポインタを使用して複数の行を切り取ります

F4
F5

#include <iostream>
using namespace std;

const int maxn = 505;
int s[maxn][maxn];

int main() {
	memset(s, 0, sizeof(s));
	int n, m, k;
	scanf("%d %d %d", &n, &m, &k);
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			scanf("%d", &s[i][j]);
			s[i][j] += s[i - 1][j];
		}
	}
	int res = 0;
	// 上下边界
	for (int up = 1; up <= n; up++) {
		for (int down = up; down <= n; down++) {
			int sum = 0;
			// 左右边界
			for (int left = 1, right = 1; right <= m; right++) {
				sum += s[down][right] - s[up - 1][right];
				while (sum > k) {
					sum -= s[down][left] - s[up - 1][left];
					left++;
				}
				res += right - left + 1;
			}
		}
	}
	printf("%d\n", res);
	return 0;
}

方法②:暴力(データの30%以上、6秒間、ゲーム中に直接の暴力は行われません!それを見てください)

#include <iostream>
using namespace std;

int mat[550][550];

int main() {
	int n, m;
	long long k;
	cin >> n >> m >> k;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			cin >> mat[i][j];
		}
	}
	long long sum = 0;
	long long cnt = 0;
	for (int h1 = 1; h1 <= n; h1++) {
		for (int h2 = h1; h2 <= n; h2++) {
			for (int l1 = 1; l1 <= m; l1++) {
				for (int l2 = l1; l2 <= m; l2++) {
					sum = 0;
					for (int h = h1; h <= h2; h++) {
						for (int l = l1; l <= l2; l++) {
							sum += mat[h][l];
						}
					}
					if (sum <= k) {
						cnt++;
					}
				}
			}
		}
	}
	cout << cnt << endl;
	return 0;
}

質問G:ブロック描画(動的計画法)

G1

【サンプル入力】

3

【出力例】

5

G2
落とし穴:忘れられがちなモジュロを取ることに注意してください!
(はい、たとえば、最後から2番目の質問のモジュロを取るのを忘れました...この
質問では、3枚の白紙を取り、n=1からn=6まで描画し、1時間書きました。dp
だと思います。パターンを見つけることですが、くそー、n = 6(3列が水平に配置されている)の状況を見逃したので、パターンを見つけることができません...

この質問のルールは、n番目の列は、前の配置とそれらの基本的な配置によって取得できるということです。
最初のケース:
dp[n]は通常の列にdp[n-1]を追加することで取得できます
2番目のケース:
dp[n]はdp[n-2]に2つの水平ブロックを追加することで取得できます
3番目のケース: dp [n]は、2つの三角形のスタックにdp [n-3]を追加することで取得できますが、これら2つの三角形をスタックする方法は2つあるため、 dp [n-3]を2倍追加する
ことに注意してください。ケース:(テスト中に555を逃しましたが、完全であるとはまだ考えていません... dp[n]はdp[n-4]に加えて左右2つを渡すことができます三角形は中央のいくつかの水平ブロックの組み合わせ。3番目の場合と同様に、この組み合わせは逆にすることができます。つまり、2つのスタッキング方法があるため、2倍のdp [n-4]を追加する必要があります。要約:dp [n] = dp [n-1] + dp [n-2] + dp [n-3] * 2 + dp [n-4] * 2 (誤解、改善予定)


#include <iostream>
using namespace std;

const long long MOD = 1e9 + 7;

const int maxn = 1e7 + 100;
long long dp[maxn];

int main() {
	int n;
	cin >> n;
	dp[0] = 1;
	dp[1] = 1;
	dp[2] = 2;
	dp[3] = 5;
	for (int i = 4; i <= n; i++) {
		// 注意每次相加后都要取余
		dp[i] = (((((dp[i - 1] + dp[i - 2]) % MOD) + dp[i - 3] * 2) % MOD) + dp[i - 4] * 2) % MOD;
	}
	cout << dp[n] << endl;
	return 0;
}

質問H:マインスイーパ(BFS)

H1

【サンプル入力】

2 1
2 2 4
4 4 2
0 0 5

【出力例】

2

H2
ゲームの30分前にBFSを見て使ってみました!
トラップ①:1つのポイントに複数の地雷と地雷除去ロケットが存在する可能性があります。地雷は、爆風範囲の境界にあるときにも爆発します。
トラップ②:地雷除去ロケットはm個ありますが、最後に答えを示すのに必要なのは整数だけです(ゲーム中に答えのm倍を出力します...)

#include <iostream>
#include <queue>
#include <cmath>
#include <map>
using namespace std;

const int maxn = 50100;
// 记录坐标和半径
int x_pos[maxn];
int y_pos[maxn];
int radius[maxn];
bool vis[maxn]; // 用来记录这个点爆炸了没有

// 用于 bfs 的 struct,更方便处理
struct point {
	int x, y, r;
	// 将结构体放入 map 中,需要自己写一个 operator 来排序,因为 map 本身是有序的
	bool operator < (const point& p) const {
		if (x == p.x) {
			if (y == p.y) {
				return r < p.y;
			}
			return y < p.y;
		}
		return x < p.x;
	}
};

map<point, int> all;

double getDis(int x1, int y1, int x2, int y2) {
	return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}

int bfs(point begin, int n) {
	int cnt = 0;
	queue<point> q;
	q.push(begin);
	while (!q.empty()) {
		point cur = q.front();
		q.pop();
		// 遍历以 2 倍半径为边长的正方形,找到其爆炸所涉及到的炸雷
		for (int i = cur.y - cur.r; i <= cur.y + cur.r; i++) {
			for (int j = cur.x - cur.r; j <= cur.x + cur.r; j++) {
				if (getDis(j, i, cur.x, cur.y) > cur.r) {
					continue;
				}
				point temp;
				temp.y = i, temp.x = j;
				for (int k = 0; k < n; k++) {
					if (!vis[k] && x_pos[k] == temp.x && y_pos[k] == temp.y) {
						temp.r = radius[k];
						q.push(temp);
						cnt++;
						all[temp]--;
						vis[k] = true; // 标记为已爆炸
					}
				}
			}
		}
	}
	return cnt;
}

int main() {
	int n, m;
	cin >> n >> m;
	for (int i = 0; i < n; i++) {
		cin >> x_pos[i] >> y_pos[i] >> radius[i];
		vis[i] = false; // 初始化都还没有爆炸
	}
	int cnt = 0;
	for (int i = 0; i < m; i++) {
		point p;
		cin >> p.x >> p.y >> p.r;
		// 我比赛时输出了 m 次结果,裂开了
		// int cnt = 0;
		cnt += bfs(p, n);
		// cout << cnt << endl;
	}
	cout << cnt << endl;
	return 0;
}

質問I:Li Bai Dajiu Enhanced Edition(3D DP /回顧展)

I1

【サンプル入力】

5 10

【出力例】

14

I2
I3
私は突然涙を流しました、そして私が解決策を書いたとき、私はモジュロをとることを忘れ5555555555
誰もがモジュロをとることを忘れないでください!

練習1:3D dp(試合後の学習のための最適化方法)

3つの次元はそれぞれ対応しています:歩数、通過した居酒屋の数、水差しに残っているワインの量
.n番目のステップでは、彼は花から来たのか、居酒屋から来たのかもしれません。 、したがって、前の動きで花に遭遇する可能性のあるすべての動きに加えて、前の動きで居酒屋に遭遇する可能性のあるすべての動きを追加します。

#include <iostream>
using namespace std;

const int MOD = 1e9 + 7;
const int maxn = 105; 
long long dp[maxn][maxn][maxn] = { 0 };

int main() {
	int n, m;
	cin >> n >> m;
	// 初始化 dp
	dp[0][0][2] = 1;
	for (int i = 1; i <= n + m; i++) {
		for (int j = 0; j <= i; j++) {
			for (int k = 0; k <= 100; k++) {
				// 遇到了花后抵达第 i 步
				dp[i][j][k] = (dp[i][j][k] + dp[i - 1][j][k + 1]) % MOD;
				// 遇到了酒馆后抵达第 i 步
				// 当 k % 2 == 0 时才有可能是从酒馆走来的,因为经过酒馆后酒就加倍了
				if (j != 0 && k % 2 == 0) {
					dp[i][j][k] = (dp[i][j][k] + dp[i - 1][j - 1][k / 2]) % MOD;
				}
			}
		}
	}
	cout << dp[n + m - 1][n][1] << endl;
	return 0;
}

練習2:バックトラック方法(ゲームで使用される方法)

一年の前後に振り返ってみる練習をしてきましたが、とても面白いと思います。
試合の30分前に見てみました!その後、試験の最後の30分は書くのに20分かかりました。
すぐにフレームワークを書いたのですが、急いでいたので、多くの質問の状況がはっきりとわからなかったため、長い間間違いを探していました。幸い、この質問の答えが間違っていれば、それよりも大きくなります。正解です。間違いを見つけるのは簡単です。

主な間違いは次のとおりです
。①合計N回、M回花を通過する
必要があります②最後に花に遭遇する必要があります
③最後に花に遭遇した後、ワインを飲む必要があります
。真ん中、ワインはヌルには使用できません

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

const int MOD = 1e9 + 7;

void backTrack(vector<char>& temp, vector<vector<char> >& ans, int n, int m, int nn, int mm, int jiu) {
	if (jiu < 0) return; // 如果遇到花却没酒了,则不符合条件
	if (nn > n || mm > m) return; // 如果经过了多于 N 次店、M 次花,则不符合条件
	if (temp.size() == n + m) {
		if (jiu == 0 && temp.back() == '0') { // 如果最后到达的是店也不符合条件
			ans.push_back(temp);
		}
		return;
	}
	
	temp.push_back('0');
	backTrack(temp, ans, n, m, nn, mm + 1, jiu - 1);
	temp.pop_back();
	temp.push_back('1');
	backTrack(temp, ans, n, m, nn + 1, mm, jiu * 2);
	temp.pop_back();
}

int main() {
	int n, m;
	cin >> n >> m;
	int jiu = 2;
	vector<char> temp;
	vector<vector<char> > ans;
	backTrack(temp, ans, n, m, 0, 0, jiu);
	cout << ans.size() % MOD << endl;
	return 0;
}

質問J:竹を切る

J1

【サンプル入力】

6
2 1 4 2 6 7

【出力例】

5

J2
J3
残り10分で時間がないので、質問を見て本当に出来ません。

要約する

①タイトルの要件に注意し、モジュロを取ることを忘れないでください!
②スコープに注意してください。長時間使用しても
かまいません③質問カードを長時間使用しないでください。たとえば、質問Eの質問を1時間理解できなかった場合は、早めに質問を変更する必要があります。そして最後に私の考えを変えて、それを見るために戻ってきます。多分それはよりよく理解されるでしょう

おすすめ

転載: blog.csdn.net/weixin_51250927/article/details/124062485
おすすめ