2022 The 13th Blue Bridge Cup Provincial Competition C/C++ Group B individual problem solving

Question A: Nine to Decimal (Math)

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;
}

Answer: 1478

Question B: Shunzi Date (language)

B
There are many controversies at present, which are divided into 3 kinds of answers: 4 , 5, and 14.
The answer I wrote during the test was 5
, but I observed that more netizens answered 4
, and the Blue Bridge Cloud class on the night after the game said 14 ( unofficial)

Let me summarize:

The first answer: 5
Look at the question. When explaining 20220123, it says that it has a straight: 123.
So it can be considered that there is only a straight of 123, and 012 is not a straight.
Then in the description of 20221023 it refers to the reversed straight of 210, but it says it is not a straight date. Therefore, it is considered that it is more clear that 0 cannot be included, and the reverse order can be regarded as a straight.

20220123
20220321
20221123
20221230
20221231

The second answer: 4
means that 012 and the reverse order (such as 210) are not considered a straight, so remove the above 20220321

20220123
20221123
20221230
20221231

The third answer:
The straight in question 14 is: three consecutive numbers, not three digits. So 012 is also a straight. From the second example 20221023, we know that the reverse order of 210 is not a straight.
If you want to count 012, then in the second example, the reverse order of 210 will be rejected.

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

I don't know the correct answer yet, I can only wait for the official explanation
orz

Question C: Brushing Statistics (Simulation)

C1

【Sample input】

10 20 99

【Example output】

8

insert image description here

Trap: Note that a, b, and n should be stored in long long
. The code written during the exam: only considering that n should be stored in long long, but not using long long to store a and b. I haven’t considered that the time may exceed the limit

#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;
}

Post-match code optimization: take the remainder first and then brute force

#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;
} 

Question D: Pruning Shrubs (Finding Patterns)

D1

【Sample input】

3

【Example output】

4
2
4

D2
First use violence to find the rules, and then simplify the code according to the rules

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

#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;
}

The result is as follows:
D2
the code can be simplified by finding the rules:

#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;
}

Question E: X-Base Subtraction (Math)

E1

【Sample input】

11
3
10 4 0
3
1 2 0

【Example output】

94

E2
I watched the game for an hour, but I couldn't understand the question orz...
This question is very abstract and difficult to understand

First, let me explain how 321 in the problem description is converted to 65.
From the question: the ones place is binary, the tens place is decimal, and the hundreds place is octal.
The first line of the title says: The base system specifies the number of digits in the digits. Meaning: 2 for each digit, 1 for tens, 10 for 10, 1 for hundreds.
First define the result sum = 0
① Look at the ones digit: the ones digit is 1, then you only need to count once to get to 1, and then add 1 to the result, that is, sum += 1
② Look at the tens digit: the tens digit is 2, because The ones digit is binary, so if the tens digit is to be 2, it needs to undergo the following transformation: 00 -> 01 -> 10 -> 11 -> 20. It can be seen that each time the tens digit is added by 1, the ones digit needs to be transformed 2 times, so to make the tens digit become 2, a total of 2 (the value of the tens digit) * 2 (the one digit hexadecimal) need to be transformed . Then add it to the result, that is, sum += 2 * 2
③ Look at the hundreds place: the hundreds place is 3. According to the analysis of the tens place, it is the same: to make the hundreds place 3, you need to transform 3 (hundred place). value) * 10 (ten's base) * 2 (one's base) times . Then add the result to it, i.e. sum += 3 * 10 * 2
To sum up: 321 converts to sum = 1 + 2 * 2 + 3 * 10 * 2 = 65

Formula:
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])
Favor: (Hata Kyushu method) setting
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])…

Code:

#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;
}

Question F: Statistical Submatrix (Prefix Sum + Double Pointer)

F1

【Sample input】

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

【Example output】

19

F2
F3
Note that k has exceeded the range of int (although I can't reach it, it has already timed out, but I still have to pay attention) I read it wrong, the value of k is 2.5 * 10 ^ 8, and the range of int is -21 4748 3648 ~ 21 4748 3647 (21 * 10^8)

Method ①: prefix sum + double pointer
First find the prefix sum of each column, and then use double pointers to cut several lines

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;
}

Method ②: Violence (over 30% of the data, no direct violence will be done during the game for 6 fors! Just look at it)

#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;
}

Question G: Block Drawing (Dynamic Programming)

G1

【Sample input】

3

【Example output】

5

G2
Pitfall: Pay attention to taking the modulo , which is often forgotten! ! !
(Yes, for example, I forgot to take the modulo for the penultimate question... This
question took me three blank sheets of paper, I drew from n = 1 to n = 6, and wrote it for an hour .I
think dp is to find the pattern, but, damn it, I missed a situation when n = 6 (three columns are placed horizontally), so I can't find the pattern...

The rule of this question is that the nth column can be obtained by the previous arrangement, plus those basic arrangements.
The first case:
dp[n] can be obtained by adding dp[n - 1] to a normal column
The second case:
dp[n] can be obtained by adding two horizontal blocks to dp[n - 2] The
third Case:
dp[n] can be obtained by adding dp[n - 3] to the stack of two triangles, but it should be noted that there are two ways to stack these two triangles , so add twice the dp[ n - 3] The
fourth case: (I missed 555 during the test, but I still haven't considered the completeness, to be perfected...
dp[n] can pass dp[n - 4] plus the left and right two A triangle is obtained by the combination of several horizontal blocks in the middle. As in the third case, this combination can be reversed, that is, there are two stacking methods, so twice the dp[n - 4] should be added. In
summary: dp[n ] = dp[n - 1] + dp[n - 2] + dp[n - 3] * 2 + dp[n - 4] * 2 (misunderstanding, to be improved)

#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;
}

Question H: Minesweeper (BFS)

H1

【Sample input】

2 1
2 2 4
4 4 2
0 0 5

【Example output】

2

H2
Half an hour before the game, I took a look at BFS and used it!
Trap ①: There can be multiple mines and demining rockets at one point. Mines are also detonated when they are on the boundary of the blast range.
Trap ②: There are m demining rockets, but only an integer is required to indicate the answer at the end (I output m times the answer during the game...)

#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;
}

Question I: Li Bai Dajiu Enhanced Edition (3D DP / Retrospective)

I1

【Sample input】

5 10

【Example output】

14

I2
I3
I burst into tears, and when I wrote the solution, I found out that I forgot to take the modulo 5555555555
Everyone must remember to take the modulo! ! !

Practice 1: 3D dp (optimization method for post-match learning)

The three dimensions correspond respectively: how many steps have been taken, how many taverns have passed, and how much wine is left
in the jug. At the nth step, he may have come from the flower, or he may have come from the tavern, So add all the possible moves to encounter the flower in the previous move, plus all the possible moves to encounter the tavern in the previous move.

#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;
}

Practice 2: Backtracking method (the method used in the game)

I have practiced retrospecting for a period of time before and after the year, and I find it very interesting.
I took a look at it half an hour before the game! ! Then the last half hour of the exam took 20 minutes to write.
I wrote the framework all at once, but I was in a hurry. I didn't see the conditions of many questions clearly, which led to a long search for mistakes. Fortunately, if the answer to this question is wrong, it is larger than the correct answer, and it is easy to find mistakes.

The main mistakes are as follows:
① A total of N times must pass through the store, M times flowers
② The last encounter must be a flower
③ After the last encounter with a flower, the wine must be drunk
④ When encountering a flower in the middle, the wine cannot be used for null

#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;
}

Question J: Chopping Bamboo

J1

【Sample input】

6
2 1 4 2 6 7

【Example output】

5

J2
J3
There are only ten minutes left, and I don't have time to do it, and I really can't do it after looking at the question.

Summarize

① Pay attention to the requirements of the title, and remember to take the modulo!
② Pay attention to the scope, you may use long long
③ Don’t work on a question card for too long. For example, if I didn’t understand the question in question E for an hour, I should change the question early, and finally change my thinking and come back to look at it. Maybe it will be better understood

Guess you like

Origin blog.csdn.net/weixin_51250927/article/details/124062485