2020年第十一屆藍橋杯javaB組省賽
文章目錄
- 試題 A: 門牌製作
- 試題 B: 尋找 2020
- 試題 C: 蛇形填數
- 試題 D: 七段碼
- 試題 E: 排序
- 試題 F: 成績分析
- 試題 G: 單詞分析
- 試題 H: 數字三角形
- 試題 I: 子串分值和
- 試題 J: 裝飾珠
以下均為個人想法和解題思路,如有錯誤或不足,歡迎指正。
試題 A: 門牌製作
本題總分:5 分
- 【問題描述】
小藍要為一條街的住戶製作門牌號。
這條街一共有 2020 位住戶,門牌號從 1 到 2020 編號。
小藍製作門牌的方法是先製作 0 到 9 這幾個數字字元,最後根據需要將字
符貼上到門牌上,例如門牌 1017 需要依次貼上字元 1、 0、 1、 7,即需要 1 個
請問要製作所有的 1 到 2020 號門牌,總共需要多少個字元 2?
- 【答案提交】
這是一道結果填空的題,你只需要算出結果後提交即可。本題的結果為一個整數,在提交答案時只填寫這個整數,填寫多餘的內容將無法得分。
個人答案:624
個人程式碼:
public class _門牌製作 {
public static void main(String[] args) {
int res = 0;
for(int i=1; i<=2020; ++i) {
int t = i;
while(t>0) {
if(t%10 == 2) {
++ res;
}
t /= 10;
}
}
System.out.println(res); //624
}
}
解題思路:第一題屬於簽到題,直接暴力就行了
試題 B: 尋找 2020
本題總分:5 分
- 【問題描述】
小藍有一個數字矩陣,裡面只包含數字 0 和 2。小藍很喜歡 2020,他想找
到這個數字矩陣中有多少個 2020 。
小藍只關注三種構成 2020 的方式:
• 同一行裡面連續四個字元從左到右構成 2020。
• 同一列裡面連續四個字元從上到下構成 2020。
• 在一條從左上到右下的斜線上連續四個字元,從左上到右下構成 2020。
例如,對於下面的矩陣:
000000
002202
000000
000022
002020
一共有 5 個 2020。其中 1 個是在同一行裡的, 1 個是在同一列裡的, 3 個
是斜線上的。
小藍的矩陣比上面的矩陣要大,由於太大了,他只好將這個矩陣放在了一
個檔案裡面,在試題目錄下有一個檔案 2020.txt,裡面給出了小藍的矩陣。
請幫助小藍確定在他的矩陣中有多少個 2020。
- 【答案提交】
這是一道結果填空的題,你只需要算出結果後提交即可。本題的結果為一個整數,在提交答案時只填寫這個整數,填寫多餘的內容將無法得分。
個人答案:16520
個人程式碼:
/**
* 使用文件編輯器開啟考試給的txt檔案,把游標定位至最後一個字元前面,可知共300行300列
*/
import java.util.Scanner;
public class _11_SS_B_尋找2020 {
static char[][] r = new char[300][300];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
for(int i=0; i<300; ++i) {
r[i] = sc.nextLine().toCharArray();
}
int res = 0;
for(int i=0; i<300; ++i) {
for(int j=0; j+3<300; ++j) {
if(r[i][j]=='2' && r[i][j+1]=='0' && r[i][j+2]=='2' && r[i][j+3]=='0')
++ res;
}
}
for(int i=0; i+3<300; ++i) {
for(int j=0; j<300; ++j) {
if(r[i][j]=='2' && r[i+1][j]=='0' && r[i+2][j]=='2' && r[i+3][j]=='0')
++ res;
}
}
for(int i=0; i+3<300; ++i) {
for(int j=0; j+3<300; ++j) {
if(r[i][j]=='2' && r[i+1][j+1]=='0' && r[i+2][j+2]=='2' && r[i+3][j+3]=='0')
++ res;
}
}
System.out.println(res); //16520
}
}
解題思路:依舊暴力
試題 C: 蛇形填數
本題總分:10 分
- 【問題描述】
如下圖所示,小明用從 1 開始的正整數“蛇形”填充無限大的矩陣。
容易看出矩陣第二行第二列中的數是 5。請你計算矩陣中第 20 行第 20 列 的數是多少?
- 【答案提交】
這是一道結果填空的題,你只需要算出結果後提交即可。本題的結果為一個整數,在提交答案時只填寫這個整數,填寫多餘的內容將無法得分。
個人答案:761
個人程式碼:
public class _蛇形填數 {
public static void main(String[] args) {
int res = 1, t = 4;
for(int i=2; i<=20; ++i) {
res += t;
t += 4;
}
System.out.println(res); //761
}
}
解題思路:
試題 D: 七段碼
本題總分:10 分
- 【問題描述】
小藍要用七段碼數碼管來表示一種特殊的文字。
上圖給出了七段碼數碼管的一個圖示,數碼管中一共有 7 段可以發光的二極體,分別標記為 a, b, c, d, e, f, g。
小藍要選擇一部分二極體(至少要有一個)發光來表達字元。在設計字元的表達時,要求所有發光的二極體是連成一片的。
- 例如: b 發光,其他二極體不發光可以用來表達一種字元。
- 例如: c 發光,其他二極體不發光可以用來表達一種字元。這種 方案與上 一行的方案可以用來表示不同的字元,儘管看上去比較相似。
- 例如: a, b, c, d, e 發光, f, g 不發光可以用來表達一種字元。
- 例如: b, f 發光,其他二極體不發光則不能用來表達一種字元,因為發光 的二極體沒有連成一片。
請問,小藍可以用七段碼數碼管表達多少種不同的字元?
- 【答案提交】
這是一道結果填空的題,你只需要算出結果後提交即可。本題的結果為一個整數,在提交答案時只填寫這個整數,填寫多餘的內容將無法得分。
個人答案:80
個人程式碼:
import java.util.ArrayList;
import java.util.HashSet;
public class _七段碼 {
static ArrayList<Integer>[] list;
static HashSet<Integer> set = new HashSet<Integer>();
public static void main(String[] args) {
init();
for(int i=0; i<7; ++i) {
vis[0] = i;
set.add(1<<i);
dfs(1, 1<<i);
}
System.out.println(set.size());
}
static int[] vis = new int[7];
public static void dfs(int n, int v) {
for(int i=0; i<n; ++i) {
for(int t : list[vis[i]]) {
int p = v|(1<<t);
if(!set.contains(p)) {
set.add(p);
vis[n] = t;
dfs(n+1, p);
}
}
}
}
/**
* 0
* 5 1
* 6
* 4 2
* 3
*/
public static void init() {
list = new ArrayList[7];
for(int i=0; i<7; ++i) {
list[i] = new ArrayList<Integer>();
}
list[0].add(1);
list[0].add(5);
list[1].add(0);
list[1].add(6);
list[1].add(2);
list[2].add(1);
list[2].add(3);
list[2].add(6);
list[3].add(2);
list[3].add(4);
list[4].add(3);
list[4].add(5);
list[4].add(6);
list[5].add(0);
list[5].add(4);
list[5].add(6);
list[6].add(1);
list[6].add(2);
list[6].add(4);
list[6].add(5);
}
}
解題思路:
試題 E: 排序
本題總分:15 分
- 【問題描述】
小藍最近學習了一些排序演算法,其中氣泡排序讓他印象深刻。在氣泡排序中,每次只能交換相鄰的兩個元素。
小藍髮現,如果對一個字串中的字元排序,只允許交換相鄰的兩個字元,則在所有可能的排序方案中,氣泡排序的總交換次數是最少的。
例如,對於字串 lan 排序,只需要 1 次交換。對於字串 qiao 排序,總共需要 4 次交換。
小藍找到了很多字串試圖排序,他恰巧碰到一個字串,需要 100 次交換,可是他忘了吧這個字串記下來,現在找不到了。
請幫助小藍找一個只包含小寫英文字母且沒有字母重複出現的字串,對該串的字元排序,正好需要 100 次交換。如果可能找到多個,請告訴小藍最短的那個。如果最短的仍然有多個,請告訴小藍字典序最小的那個。請注意字串中不可以包含相同的字元。
- 【答案提交】
這是一道結果填空的題,你只需要算出結果後提交即可。本題的結果為一個整數,在提交答案時只填寫這個整數,填寫多餘的內容將無法得分。
個人答案:jonmlkihgfedcba
個人程式碼:
public class _排序{
public static void main(String[] args) {
for(int i=1; i<20; ++i) {
System.out.println(i+":"+((i-1)*i/2)); //由此可以發現15個字元的逆序通過冒泡交換成順序所需要的交換次數最接近100,因此僅需要將onmlkjihgfedcba的第六位移動至第一位即可:jonmlkihgfedcba
}
}
}
解題思路:
試題 F: 成績分析
時間限制: 1.0s 記憶體限制: 512.0MB 本題總分:15 分
- 【問題描述】
小藍給學生們組織了一場考試,卷面總分為 100 分,每個學生的得分都是 一個 0 到 100 的整數。
請計算這次考試的最高分、最低分和平均分。
- 【輸入格式】
輸入的第一行包含一個整數 n,表示考試人數。 接下來 n 行,每行包含一個 0 至 100 的整數,表示一個學生的得分。
- 【輸出格式】
輸出三行。
第一行包含一個整數,表示最高分。
第二行包含一個整數,表示最低分。
第三行包含一個實數,四捨五入保留正好兩位小數,表示平均分。
- 【樣例輸入】
7
80
92
56
74
88
99
10
- 【樣例輸出】
99
10
71.29
- 【評測用例規模與約定】
對於 50% 的評測用例,1≤n≤100。
對於所有評測用例,1≤n≤10000。
個人程式碼:
import java.util.Scanner;
public class _11_SS_B_成績分析 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int max = Integer.MIN_VALUE, min = Integer.MAX_VALUE;
double sum = 0;
for(int i=0; i<n; ++i) {
int t = sc.nextInt();
sum += t;
max = t>max?t:max;
min = t<min?t:min;
}
System.out.println(max);
System.out.println(min);
System.out.println(String.format("%.2f", sum/n));
}
}
解題思路:
試題 G: 單詞分析
時間限制: 1.0s 記憶體限制: 512.0MB 本題總分:20 分
- 【問題描述】
小藍正在學習一門神奇的語言,這門語言中的單詞都是由小寫英文字母組 成,有些單詞很長,遠遠超過正常英文單詞的長度。小藍學了很長時間也記不 住一些單詞,他準備不再完全記憶這些單詞,而是根據單詞中哪個字母出現得 最多來分辨單詞。
現在,請你幫助小藍,給了一個單詞後,幫助他找到出現最多的字母和這 個字母出現的次數。
- 【輸入格式】
輸入一行包含一個單詞,單詞只由小寫英文字母組成。
- 【輸出格式】
輸出兩行,第一行包含一個英文字母,表示單詞中出現得最多的字母是哪 個。如果有多個字母出現的次數相等,輸出字典序最小的那個。
第二行包含一個整數,表示出現得最多的那個字母在單詞中出現的次數。
- 【樣例輸入】
lanqiao
- 【樣例輸出】
a
2
- 【樣例輸入】
longlonglongistoolong
- 【樣例輸出】
o
6
- 【評測用例規模與約定】
對於所有的評測用例,輸入的單詞長度不超過 1000。
個人程式碼:
import java.util.Scanner;
public class _11_SS_B_單詞分析 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
char[] ch = sc.nextLine().toCharArray();
int[] r = new int[26];
for(int i=0; i<ch.length; ++i) {
++ r[ch[i]-'a'];
}
char res = 'a';
int max = Integer.MIN_VALUE;
for(int i=0; i<r.length; ++i) {
if(r[i]>max) {
res = (char)('a'+i);
max = r[i];
}
}
System.out.println(res);
System.out.println(max);
}
}
解題思路:
試題 H: 數字三角形
時間限制: 1.0s 記憶體限制: 512.0MB 本題總分:20 分
- 【問題描述】
上圖給出了一個數字三角形。從三角形的頂部到底部有很多條不同的路徑。 對於每條路徑,把路徑上面的數加起來可以得到一個和,你的任務就是找到最 大的和。
路徑上的每一步只能從一個數走到下一層和它最近的左邊的那個數或者右 邊的那個數。此外,向左下走的次數與向右下走的次數相差不能超過 1。
- 【輸入格式】
輸入的第一行包含一個整數 N (1 < N ≤ 100),表示三角形的行數。下面的 N 行給出數字三角形。數字三角形上的數都是 0 至 100 之間的整數。
- 【輸出格式】
輸出一個整數,表示答案。
- 【樣例輸入】
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
- 【樣例輸出】
27
個人程式碼:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
public class _11_SS_B_數字三角形 {
public static void main(String[] args) throws IOException {
InputReader sc = new InputReader(System.in);
int n = sc.nextInt();
int[][] r = new int[n][n];
for(int i=0; i<n; ++i) {
for(int j=0; j<=i; ++j) {
r[i][j] = sc.nextInt();
}
}
int[][][] dp = new int[n][n][n+1];
dp[0][0][0] = r[0][0];
for(int i=0; i<n-1; ++i) {
for(int j=0; j<=i; ++j) {
for(int k=0; k<n; ++k) {
if(dp[i][j][k] != 0) {
dp[i+1][j][k] = Math.max(dp[i+1][j][k], dp[i][j][k]+r[i+1][j]);
dp[i+1][j+1][k+1] = Math.max(dp[i+1][j+1][k+1], dp[i][j][k]+r[i+1][j+1]);
}
}
}
}
int res = Integer.MIN_VALUE;
boolean ping = (n%2 != 0);
for(int i=0; i<n; ++i) {
res = Math.max(res, dp[n-1][i][n/2]);
if(ping) {
res = Math.max(res, dp[n-1][i][(n/2)+1]);
}
}
System.out.println(res);
}
static class InputReader {
StreamTokenizer tokenizer;
public InputReader(InputStream stream) {
tokenizer = new StreamTokenizer(new BufferedReader(new InputStreamReader(stream)));
tokenizer.ordinaryChars(33, 126);
tokenizer.wordChars(33, 126);
}
public String next() throws IOException {
tokenizer.nextToken();
return tokenizer.sval;
}
public int nextInt() throws IOException {
return Integer.parseInt(next());
}
}
}
解題思路:
試題 I: 子串分值和
時間限制: 3.0s 記憶體限制: 512.0MB 本題總分:25 分
- 【問題描述】
對於一個字串 S,我們定義 S 的分值 f(S) 為 S 中出現的不同的字元個 數。例如 f(”aba”) = 2,f(”abc”) = 3, f(”aaa”) = 1。 現在給定一個字串 S[0…n−1](長度為 n),請你計算對於所有 S 的非空 子串 S[i…j](0≤i≤ j < n),f(S[i…j]) 的和是多少。
- 【輸入格式】
輸入一行包含一個由小寫字母組成的字串 S。
- 【輸出格式】
輸出一個整數表示答案。
- 【樣例輸入】
ababc
- 【樣例輸出】
28
- 【樣例說明】
子串 f值
a 1
ab 2
aba 2
abab 2
ababc 3
b 1
ba 2
bab 2
babc 3
a 1
ab 2
abc 3
b 1
bc 2
c 1
- 【評測用例規模與約定】
對於 20% 的評測用例,1≤n≤10;
對於 40% 的評測用例,1≤n≤100;
對於 50% 的評測用例,1≤n≤1000;
對於 60% 的評測用例,1≤n≤10000;
對於所有評測用例,1≤n≤100000。
個人程式碼:
import java.util.Arrays;
import java.util.Scanner;
public class _11_SS_B_子串分值和 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
char[] ch = sc.nextLine().toCharArray();
boolean[] vis = new boolean[26];
int size = 0;
long res = 0;
for(int i=0; i<ch.length; ++i) {
Arrays.fill(vis, false);
size = 0;
for(int j=i; j<ch.length; ++j) {
if(!vis[ch[j]-'a']) {
++ size;
vis[ch[j]-'a'] = true;
}
res += size;
}
}
System.out.println(res);
}
}
解題思路:這題不會這麼簡單,上述寫法應該只能拿到小部分的分
試題 J: 裝飾珠
時間限制: 5.0s 記憶體限制: 512.0MB 本題總分:25 分
- 【問題描述】
在怪物獵人這一款遊戲中,玩家可以通過給裝備鑲嵌不同的裝飾珠來獲取
相應的技能,以提升自己的戰鬥能力。
已知獵人身上一共有 6 66 件裝備,每件裝備可能有若干個裝飾孔,每個裝飾
孔有各自的等級,可以鑲嵌一顆小於等於自身等級的裝飾珠 (也可以選擇不鑲
嵌)。
裝飾珠有M種,編號1至M,分別對應M 種技能,第i種裝飾珠的等級
為Li,只能鑲嵌在等級大於等於Li的裝飾孔中。
對第i種技能來說,當裝備相應技能的裝飾珠數量達到Ki個時,會產生Wi(Ki) 的價值。鑲嵌同類技能的數量越多,產生的價值越大,即Wi(Ki − 1) < Wi(Ki) 。但每個技能都有上限Pi(1 ≤ P i ≤ 7) ,當裝備的珠子數量超過Pi時,只會產生Wi(Pi) 的價值。
對於給定的裝備和裝飾珠資料,求解如何鑲嵌裝飾珠,使得 6 件裝備能得
到的總價值達到最大。
- 【輸入格式】
輸入的第1至6行,包含6件裝備的描述。其中第i的第一個整數Ni表示
第i件裝備的裝飾孔數量。後面緊接著Ni個整數,分別表示該裝備上每個裝飾
孔的等級L(1 ≤ L ≤ 4) 。
第7行包含一個正整數M,表示裝飾珠 (技能) 種類數量。
第8至 M + 7行,每行描述一種裝飾珠 (技能) 的情況。每行的前兩個整數Lj(1 ≤ Lj ≤ 4)和Pj(1 ≤ Pi ≤ 7)分別表示第j種裝飾珠的等級和上限。接下來Pj個整數,其中第k個數表示裝備該中裝飾珠數量為k時的價值 Wj(k)。
- 【輸出格式】
輸出一行包含一個整數,表示能夠得到的最大價值。
- 【樣例輸入】
1 1
2 1 2
1 1
2 2 2
1 1
1 3
3
1 5 1 2 3 5 8
2 4 2 4 8 15
3 2 5 10
- 【樣例輸出】
20
- 【樣例說明】
按照如下方式鑲嵌珠子得到最大價值 18,括號內表示鑲嵌的裝飾珠的種類編號:
1: (1)
2: (1) (2)
3: (1)
4: (2) (2)
5: (1)
6: (2)
4 顆技能 1 裝飾珠,4 顆技能 2 裝飾珠 W1(4) + W2(4) = 5 + 15 = 20。
- 【評測用例規模與約定】
對於 30% 的評測用例,1 ≤ Ni ≤ 10, 1 ≤ M ≤ 20, 1 ≤ Wj(k) ≤ 500;
對於所有評測用例,1 ≤ Ni ≤ 50, 1 ≤ M ≤ 10000, 1 ≤ Wj(k) ≤ 10000。