2020第十一届蓝桥杯软件类省赛第二场C/C++ 大学 B 组(题解)
試題 A: 門牌制作
問題描述
小藍要為一條街的住戶制作門牌號。
這條街一共有 2020 位住戶,門牌號從 1 到 2020 編號。
小藍制作門牌的方法是先制作 0 到 9 這幾個數字字符,最后根據需要將字
符粘貼到門牌上,例如門牌 1017 需要依次粘貼字符 1、 0、 1、 7,即需要 1 個
字符 0, 2 個字符 1, 1 個字符 7。
請問要制作所有的 1 到 2020 號門牌,總共需要多少個字符 2?
直接暴力
/*Author : lifehappy */ #include <bits/stdc++.h>using namespace std;int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);int ans = 0;for(int i = 1; i <= 2020; i++) {int temp = i;while(temp) {if(temp % 10 == 2) ans++;temp /= 10;}}printf("%d\n", ans);return 0; } /* 624 */試題 B: 既約分數
【問題描述】
如果一個分數的分子和分母的最大公約數是 1,這個分數稱為既約分數。
例如,34,52,18,71\frac{3}{4}, \frac{5}{2}, \frac{1}{8}, \frac{7}{1}43?,25?,81?,17?都是既約分數。
請問,有多少個既約分數,分子和分母都是 1 到 2020 之間的整數(包括 1
和 2020)?
顯然這不是一道簡單題,我們寫下數學式子來
∑i=1n∑j=1n[gcd(i,j)=1]∑k=1nμ(k)∑i=1nk∑j=1nk\sum_{i = 1} ^{n} \sum_{j = 1} ^{n} [gcd(i, j) = 1]\\ \sum_{k = 1} ^{n} \mu(k) \sum_{i = 1} ^{\frac{n}{k}} \sum_{j = 1} ^{\frac{n}{k}}\\ i=1∑n?j=1∑n?[gcd(i,j)=1]k=1∑n?μ(k)i=1∑kn??j=1∑kn??
然后就只要線性篩,加數論分塊即可。
試題 C: 蛇形填數
如下圖所示,小明用從 1 開始的正整數“蛇形”填充無限大的矩陣。
1 2 6 7 15 :::
3 5 8 14 :::
4 9 13 :::
10 12 :::
11 :::
:::
容易看出矩陣第二行第二列中的數是 5。請你計算矩陣中第 20 行第 20 列
的數是多少 ?
這題也是模擬即可,所以就直接上代碼吧,看代碼就懂了。
/*Author : lifehappy */ #include <bits/stdc++.h>using namespace std;int a[50][50];int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);int n = 45, num = 45 * 45;for(int i = 1, cnt = 1; i <= n && cnt <= num; i++) {if(i & 1) {for(int x = i, y = 1; x >= 1 && y <= i; x--, y++) {a[x][y] = cnt++;}}else {for(int x = 1, y = i; x <= i && y >= 1; x++, y--) {a[x][y] = cnt++;}}}printf("%d\n", a[20][20]);return 0; } /* 761 */試題 D: 跑步鍛煉
【問題描述】
小藍每天都鍛煉身體。
正常情況下,小藍每天跑 1 千米。如果某天是周一或者月初(1 日),為了
激勵自己,小藍要跑 2 千米。如果同時是周一或月初,小藍也是跑 2 千米。
小藍跑步已經堅持了很長時間,從 2000 年 1 月 1 日周六(含)到 2020 年
10 月 1 日周四(含)。請問這段時間小藍總共跑步多少千米?
按照天數去模擬就OK了。
/*Author : lifehappy */ #include <bits/stdc++.h>using namespace std;int day[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);int a = 2000, b = 1, c = 1, num = 1, ans = 0;while(a != 2020 || b != 10 || c != 2) {if(c == 1 || num % 7 == 3) ans += 2;else ans += 1;int nowday = day[b];if((a % 400 == 0 || (a % 4 == 0 && a % 100 != 0)) && b == 2) nowday++;c++, num++;if(c > nowday) {c = 1;b += 1;}if(b == 13) {a += 1;b = 1;}}printf("%d\n", ans);return 0; } /* 8879 */試題 E: 七段碼
總共有7根管子,二進制枚舉,然后bfs或者dfs判斷是否聯通即可。
下面用0 -> a, 1 -> b……6 -> g,也就是用0代表a,以此類推,,
/*Author : lifehappy */ #include <bits/stdc++.h>using namespace std;bool judge(int pos, int value) {queue<int> q;q.push(pos);value ^= 1ll << pos;while(q.size()) {int temp = q.front();q.pop();if(temp == 0) {if(value >> 1 & 1) {value ^= 1 << 1;q.push(1);}if(value >> 5 & 1) {value ^= 1 << 5;q.push(5);}}else if(temp == 1) {if(value >> 0 & 1) {value ^= 1 << 0;q.push(0);}if(value >> 2 & 1) {value ^= 1 << 2;q.push(2);}if(value >> 6 & 1) {value ^= 1 << 6;q.push(6);}}else if(temp == 2) {if(value >> 1 & 1) {value ^= 1 << 1;q.push(1);}if(value >> 3 & 1) {value ^= 1 << 3;q.push(3);}if(value >> 6 & 1) {value ^= 1 << 6;q.push(6);}}else if(temp == 3) {if(value >> 2 & 1) {value ^= 1 << 2;q.push(2);}if(value >> 4 & 1) {value ^= 1 << 4;q.push(4);}}else if(temp == 4) {if(value >> 3 & 1) {value ^= 1 << 3;q.push(3);}if(value >> 5 & 1) {value ^= 1 << 5;q.push(5);}if(value >> 6 & 1) {value ^= 1 << 6;q.push(6);}}else if(temp == 5) {if(value >> 0 & 1) {value ^= 1 << 0;q.push(0);}if(value >> 4 & 1) {value ^= 1 << 4;q.push(4);}if(value >> 6 & 1) {value ^= 1 << 6;q.push(6);}}else {if(value >> 1 & 1) {value ^= 1 << 1;q.push(1);}if(value >> 2 & 1) {value ^= 1 << 2;q.push(2);}if(value >> 4 & 1) {value ^= 1 << 4;q.push(4);}if(value >> 5 & 1) {value ^= 1 << 5;q.push(5);}}}return value == 0; }int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);int ans = 0;for(int i = 1; i < 1 << 7; i++) {int j;for(j = 0; j < 7; j++) {if(i >> j & 1) {break;}}if(judge(j, i)) {ans++;}}printf("%d\n", ans);return 0; } /* 80 */試題 F: 成績統計
統計≥60\geq 60≥60和≥85\geq 85≥85的數量,然后按照要求四舍五入即可。
/*Author : lifehappy */ #include <bits/stdc++.h>using namespace std;int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);int n, a, res = 0, ans = 0;scanf("%d", &n);for(int i = 1; i <= n; i++) {scanf("%d", &a);if(a >= 60) res++;if(a >= 85) ans++;}printf("%.0f%%\n%.0f%%\n", (double)res * 100.0 / n, (double)ans * 100.0 / n);return 0; }試題 G: 回文日期
跟D題一樣,按照天數模擬,然后再judge就行了。
/*Author : lifehappy */ #include <bits/stdc++.h>using namespace std;int day[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};bool judge1(int a, int b, int c) {int d = a * 10000 + b * 100 + c;int num[10], cnt = 9;while(d) {num[--cnt] = d % 10;d /= 10;}for(int l = 1, r = 8; l < r; l++, r--) {if(num[l] != num[r]) {return false;}}return true; }bool judge2(int a, int b, int c) {int d = a * 10000 + b * 100 + c;int num[10], cnt = 9;while(d) {num[--cnt] = d % 10;d /= 10;}for(int l = 1, r = 8; l < r; l++, r--) {if(num[l] != num[r] || num[l] != num[l & 1 ? 1 : 2]) {return false;}}return true; }int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);int a, b, c, d, flag = 0;scanf("%d", &d);a = d / 10000, b = (d / 100) % 100, c = d % 100;while(flag < 2) {int nowday = day[b];if(((a % 400 == 0) || (a % 4 == 0 && a % 100 != 0)) && b == 2) nowday++;c++;if(c > nowday) {c = 1;b += 1;}if(b == 13) {a += 1;b = 1;}if(!flag && judge1(a, b, c)) {printf("%d%02d%02d\n", a, b, c);flag += 1;}if(judge2(a, b, c)) {printf("%d%02d%02d\n", a, b, c);flag += 1;}}return 0; }試題 H: 子串分值和
這題稍微有點思維吧,我們定義,對于一個字符串我們只記錄這個字母在這個字符中出現的第一次有貢獻,
接下來就是統計,以某個字符為第一次出現的字母的字串數量了,
我們定義last[i]last[i]last[i]表示字符iii在當前枚舉點之前最后一次出現的位置,顯然這個字符的左端點就可以落在[last[i]+1,now][last[i] + 1, now][last[i]+1,now]
這個區間了,然后右端點可以在now,nnow, nnow,n區間,所有的字串就是這兩個長度的乘積,然后就是非常簡短的代碼了。
/*Author : lifehappy */ #include <bits/stdc++.h>using namespace std;typedef long long ll;const int N = 1e5 + 10;int last[30], n;char str[N];int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);scanf("%s", str + 1);n = strlen(str + 1);ll ans = 0;for(int i = 1; i <= n; i++) {ans += 1ll * (i - last[str[i] - 'a']) * (n - i + 1);last[str[i] - 'a'] = i;}printf("%lld\n", ans);return 0; }試題 I: 平面切分
平面上有 N 條直線,其中第 i 條直線是y=Ai?x+Biy = A_i · x + B_iy=Ai??x+Bi?。
請計算這些直線將平面分成了幾個部分。
試題 J: 字串排序
【問題描述】
小藍最近學習了一些排序算法,其中冒泡排序讓他印象深刻。
在冒泡排序中,每次只能交換相鄰的兩個元素。
小藍發現,如果對一個字符串中的字符排序,只允許交換相鄰的兩個字符,
則在所有可能的排序方案中,冒泡排序的總交換次數是最少的。
例如,對于字符串 lan 排序,只需要 1 次交換。對于字符串 qiao 排序,
總共需要 4 次交換。
小藍的幸運數字是 V,他想找到一個只包含小寫英文字母的字符串,對這
個串中的字符進行冒泡排序,正好需要 V 次交換。請幫助小藍找一個這樣的字
符串。如果可能找到多個,請告訴小藍最短的那個。如果最短的仍然有多個,
請告訴小藍字典序最小的那個。請注意字符串中可以包含相同的字符。
思路
顯然要使長度最短,我們就不能浪費每一個字母,所以,一定有字母是遞減的順序的,
要使字典序最短,每個字母出現的數量一定是要從前往后遞增的,這樣就好了,,
限制一下每個字母最多出現的次數然后就是dfsdfsdfs爆搜,
但是考場上限制的次數太小了,寫了777,只能測到910009100091000左右的測試點,改到888就好了。
(這題貌似好像有點問題,并不是正解 >_<)
/*Author : lifehappy */ #include <bits/stdc++.h>using namespace std;const int N = 1e4 + 10;char ans[N], res[N];int n, len;bool judge() {int i = len;while(ans[i] == res[i] && i) i--;return res[i] < ans[i]; }void dfs(int now, int maxn, int m, int sum) {if(sum == n) {if(m < len || (m == len && judge())) {len = m;for(int i = 1; i <= len; i++) {ans[i] = res[i];}}return ;}if(now >= 26) return ;for(int i = 1; i <= maxn; i++) {int temp = sum + m * i;if(temp > n) return ;res[m + i] = char(now + 'a');dfs(now + 1, i, m + i, temp);} }int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);len = 0x3f3f3f3f;scanf("%d", &n);dfs(0, 8, 0, 0);for(int i = len; i >= 1; i--) {putchar(ans[i]);}puts("");return 0; } 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的2020第十一届蓝桥杯软件类省赛第二场C/C++ 大学 B 组(题解)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 体内寒湿气重怎么祛除
- 下一篇: C++ 从文件夹中读取文件