1. 程式人生 > 實用技巧 >2020年第十一屆藍橋杯國賽 B組個人題解

2020年第十一屆藍橋杯國賽 B組個人題解

目錄

試題下載

試題 A: 美麗的 2

本題總分:5 分
【問題描述】
小藍特別喜歡 \(2\),今年是公元 \(2020\) 年,他特別高興。
他很好奇,在公元 \(1\) 年到公元 \(2020\) 年(包含)中,有多少個年份的數位中 包含數字 \(2?\)
【我的題解】
數位分離,水題了。迴圈 \(1\)\(2020\),寫個函式判斷一下就好了

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <set>
#include <queue>

using namespace std;
typedef long long LL;
typedef pair<int, int> PII;

bool hasDigitTwo(int number) {
	while (number) {
		if (number % 10 == 2) {
			return true;
		}
		number /= 10;
	}
	return false;
}

int main() {
	int answer = 0;
	for (int i = 1; i <= 2020; i++) {
		if (hasDigitTwo(i)) {
			answer++;
		}
	}
	printf("%d\n", answer);
	return 0;
}

我的答案 \(563\)

試題 B: 擴散

本題總分:5 分
【問題描述】
小藍在一張無限大的特殊畫布上作畫。
這張畫布可以看成一個方格圖,每個格子可以用一個二維的整數座標表示。
小藍在畫布上首先點了一下幾個點:(0,0), (2020,11), (11,14), (2000,2000)。 只有這幾個格子上有黑色,其它位置都是白色的。
每過一分鐘,黑色就會擴散一點。具體的,如果一個格子裡面是黑色,它 就會擴散到上、下、左、右四個相鄰的格子中,使得這四個格子也變成黑色 (如果原來就是黑色,則還是黑色)。
請問,經過 \(2020\) 分鐘後,畫布上有多少個格子是黑色的。
【我的題解】
一開始寫了個按層遍歷的 \(bfs\)

, 發現執行不出結果,然後換了思路。將題目換種問法,求無限大的畫布裡與給出的四個點中至少一個點曼哈頓距離小於等於 \(2020\) 的點有多少個。那麼就可以想到, \(x\) 座標小於 \(-3000\) 或者大於 \(5000\) 的點不可能滿足這個條件,同理 \(y\) 座標小於 \(-3000\) 或者大於 \(5000\) 的點也不可能滿足這個條件。那麼無限大的畫布就有範圍了,列舉這個範圍內的點,統計有多少個滿足條件的就好了。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
#include <set>
#include <queue>

using namespace std;
typedef long long LL;
typedef pair<int, int> PII;

const PII POINTS[] = {{0, 0}, {2020, 11}, {11, 14}, {2000, 2000}};

bool isBlack(int x, int y, int i) {
	int disX = x - POINTS[i].first;
	int disY = y - POINTS[i].second;
	return abs(disX) + abs(disY) <= 2020;
}

int main() {
	int answer = 0;
	for (int i = -3000; i <= 5000; i++) {
		for (int j = -3000; j <= 5000; j++) {
			for (int k = 0; k < 4; k++) {
				if (isBlack(i, j, k)) {
					answer++;
					break;
				}
			}
		}
	}
	printf("%d\n", answer);
	return 0;
}

試題 C: 階乘約數

本題總分:10 分
【問題描述】
定義階乘 \(n! = 1 \times 2 \times 3 \times ··· \times n\)
請問 \(100!\)\(100\) 的階乘)有多少個約數。
【我的題解】
對於一個大於 \(1\) 的正整數 \(n\) 可以分解質因數 \(n = \prod_{i = 1} ^ {k} p_{i} ^ {a_{i}} = p_{1} ^ {a_{1}} . p_{2} ^ {a_{2}} ...... p_{k} ^ {a_{k}}\)
\(n\) 的正約數個數就是 \(f(n) = \prod_{i = 1} ^ {k} (a_{i} + 1) = (a_{1} + 1) . (a_{2} + 1) ...... (a_{k} + 1)\)

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
#include <set>
#include <queue>

using namespace std;
typedef long long LL;
typedef pair<int, int> PII;

vector<int> primes;
vector<int> counter;

bool isPrime(int n) {
	for (int i = 2; i * i <= n; i++) {
		if (n % i == 0) {
			return false;
		}
	}
	return true;
}

void helper(int number) {
	int pos = 0;
	while (primes[pos] <= number) {
		while (number % primes[pos] == 0) {
			number /= primes[pos];
			counter[pos]++;
		}
		pos += 1;
	}
}

int main() {
	for (int i = 2; i <= 200; i++) {
		if (isPrime(i)) {
			primes.push_back(i);
			counter.push_back(0);
		}
	}

	for (int i = 1; i <= 100; i++) {
		helper(i);
	}

	LL answer = 1;
	for (int i = 0; i < counter.size(); i++) {
		answer *= (counter[i] + 1);
	}
	printf("%lld\n", answer);
	return 0;
}

我的答案 \(39001250856960000\)
【吐槽一下】
比賽的時候累乘 \(counter[i]\) 忘了 +1, 第一個迴圈只迴圈到了 \(100\),然後這10分就白給了。更離譜的是一樣的程式碼帶回來在自己的CodeBlock上執行崩潰,但是在學校比賽的時候Dev居然能跑出一個奇怪的數字。

試題 D: 本質上升序列

【問題描述】
小藍特別喜歡單調遞增的事物。
在一個字串中,如果取出若干個字元,將這些字元按照在字串中的順 序排列後是單調遞增的,則成為這個字串中的一個單調遞增子序列。
例如,在字串 \(lanqiao\) 中,如果取出字元 \(n\)\(q\),則 \(nq\) 組成一個單 調遞增子序列。類似的單調遞增子序列還有 \(lnq、i、ano\) 等等。
小藍髮現,有些子序列雖然位置不同,但是字元序列是一樣的,例如取第 二個字元和最後一個字元可以取到 \(ao\),取最後兩個字元也可以取到 \(ao\)。小藍 認為他們並沒有本質不同。
對於一個字串,小藍想知道,本質不同的遞增子序列有多少個?
例如,對於字串 \(lanqiao\),本質不同的遞增子序列有 \(21\) 個。它們分別 是 \(l\)\(a\)\(n\)\(q\)\(i\)\(o\)\(ln\)\(an\)\(lq\)\(aq\)\(nq\)\(ai\)\(lo\)\(ao\)\(no\)\(io\)\(lnq\)\(anq\)\(lno\)\(ano\)\(aio\)
請問對於以下字串(共 \(200\) 個小寫英文字母,分四行顯示):(如果你把 以下文字複製到文字檔案中,請務必檢查複製的內容是否與文件中的一致。在 試題目錄下有一個檔案 inc.txt,內容與下面的文字相同)
\(tocyjkdzcieoiodfpbgcncsrjbhmugdnojjddhllnofawllbhf\) \(iadgdcdjstemphmnjihecoapdjjrprrqnhgccevdarufmliqij\) \(gihhfgdcmxvicfauachlifhafpdccfseflcdgjncadfclvfmad\) \(vrnaaahahndsikzssoywakgnfjjaihtniptwoulxbaeqkqhfwl\)
本質不同的遞增子序列有多少個?
【我的題解】
動態規劃,\(dp[i]\) 表示前 \(i\) 個字母的本質不同遞增子序列個數
\(dp[i] = \sum_{j = last[s[i]] + 1} ^ {i - 1} (s[j] \lt s[i]) \times dp[j]\)
\(last[s[i]]\) 表示 \(s[i]\) 這個字母上一次出現的位置

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
#include <set>
#include <queue>

using namespace std;
typedef long long LL;
typedef pair<int, int> PII;

int last[30];
LL dp[210];
char s[210];

int main() {
	// freopen("inc.txt", "r", stdin);
	scanf("%s", s + 1);

	LL answer = 0;
	memset(last, -1, sizeof(last));

	dp[0] = 1;
	for (int i = 1; s[i]; i++) {
		int val = s[i] - 'a';
		for (int j = last[val] + 1; j < i; j++) {
			if (s[j] < s[i]) {
				dp[i] += dp[j];
			}
		}
		last[val] = i;
		answer += dp[i];
	}
	printf("%lld\n", answer);
	
	return 0;
}

我的答案 \(552\)

試題 E: 玩具蛇

本題總分:15 分
【問題描述】
小藍有一條玩具蛇,一共有 \(16\) 節,上面標著數字 \(1\)\(16\)。每一節都是一 個正方形的形狀。相鄰的兩節可以成直線或者成 \(90\) 度角。
小藍還有一個 \(4 \times 4\) 的方格盒子,用於存放玩具蛇,盒子的方格上依次標著 字母 \(A\)\(P\)\(16\) 個字母。
小藍可以摺疊自己的玩具蛇放到盒子裡面。他發現,有很多種方案可以將 玩具蛇放進去。
請幫小藍計算一下,總共有多少種不同的方案。如果兩個方案中,存在玩 具蛇的某一節放在了盒子的不同格子裡,則認為是不同的方案。
【我的題解】
一個 \(dfs\) 就完事兒啦,作為E題倒是比想象中簡單,不過我好像寫複雜了,不需要壓縮成一維。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
#include <set>
#include <queue>

using namespace std;
typedef long long LL;
typedef pair<int, int> PII;

const int DIRCTIONX[] = {1, -1, 0, 0};
const int DIRCTIONY[] = {0, 0, 1, -1};

int answer;
bool visited[16];
int length;

void dfs(int n) {
	if (length == 16) {
		answer++;
		return;
	}
	for (int i = 0; i < 4; i++) {
		int x = n / 4 + DIRCTIONX[i];
		int y = n % 4 + DIRCTIONY[i];
		if (x < 0 || x >= 4 || y < 0 || y >= 4) {
			continue;
		}
		int nextN = 4 * x + y;
		if (!visited[nextN]) {
			visited[nextN] = true;
			length++;
			dfs(nextN);
			visited[nextN] = false;
			length--;
		}
	}
}

int main() {
	for (int i = 0; i < 16; i++) {
		visited[i] = true;
		length++;
		dfs(i);
		visited[i] = false;
		length--;
	}
	printf("%d\n", answer);
	return 0;
}

試題 F: 皮亞諾曲線距離

時間限制: 1.0s  記憶體限制: 256.0MB  本題總分:15 分
【問題描述】
這裡就略了,下載連結已給出,可以自行下載檢視
【輸入格式】
輸入的第一行包含一個正整數 \(k\),皮亞諾曲線的階數。 第二行包含兩個整數 \(x1, y1\),表示第一個點的座標。
第三行包含兩個整數 \(x2, y2\),表示第二個點的座標。
【輸出格式】
輸出一個整數,表示給定的兩個點之間的距離。
【評測用例規模與約定】
對於 \(30\%\) 的評測用例,\(0 \le k \le 10\)
對於 \(50\%\) 的評測用例,\(0 \le k \le 20\)
對於所有評測用例,\(0 \le k \le 100, 0 \le x1,y1,x2,y2 \le 3k, x1,y1,x2,y2 \le 10 ^ {18}\)。 資料保證答案不超過 \(10 ^ {18}\)
【我的題解】
並不會做,口胡一波吧,遞迴是肯定要的,然後想到的就是以 \((0, 0)\) 為基準,求出 \((x_{1}, y_{1})\) 到基準的距離,求出 \((x_{2}, y_{2})\) 到基準的距離,然後減一下。這個遞迴感覺有點複雜呀,作為程式設計大題第一題有點搞心態。

東西有點多,未完待續