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\)
#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})\) 到基準的距離,然後減一下。這個遞迴感覺有點複雜呀,作為程式設計大題第一題有點搞心態。