2020年第十一届蓝桥杯省赛第二场Java B组 总结


比赛完,觉得省一悬了。                                ---- 2020.10.17

没想到还有省一。                                           ---- 2020.10.26



    • 结果填空题
      • 试题 A: 门牌制作(5分)
      • 试题 B: 寻找 2020(5分)
      • 试题 C: 蛇形填数(10分)
      • 试题 D: 七段码(10分)
      • 试题 E: 排序(15分)
    • 程序设计题
      • 试题 F: 成绩分析(15分)
      • 试题 G: 单词分析 (20分)
      • 试题 H: 数字三角形(20分)
      • 试题 I: 子串分值和(25分)




结果填空题


试题 A: 门牌制作(5分)

【问题描述】

小蓝要为一条街的住户制作门牌号。
这条街一共有 2020 位住户,门牌号从 1 到 2020 编号。
小蓝制作门牌的方法是先制作 0 到 9 这几个数字字符,最后根据需要将字
符粘贴到门牌上,例如门牌 1017 需要依次粘贴字符 1、 0、 1、 7,即需要 1 个
字符 0, 2 个字符 1, 1 个字符 7。
请问要制作所有的 1 到 2020 号门牌,总共需要多少个字符 2?

【答案提交】

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。


答案解析

答案是 624。

直接从 1 到 2020 遍历,每个数都拆解一遍,出现 2,计数器就加 1。

public class Main{
     

    public static void main(String[] args) {
     
        // TODO Auto-generated method stub
        int ans = 0;
        for (int i=1;i<=2020;i++) {
     
            int x = i;
            while (x>0) {
     
                if (x%10==2)    ans++;
                x /= 10;
            }
        }
        System.out.println(ans);
    }

}


试题 B: 寻找 2020(5分)

【问题描述】

小蓝有一个数字矩阵,里面只包含数字 0 和 2。小蓝很喜欢 2020,他想找
到这个数字矩阵中有多少个 2020 。
小蓝只关注三种构成 2020 的方式:
• 同一行里面连续四个字符从左到右构成 2020。
• 同一列里面连续四个字符从上到下构成 2020。
• 在一条从左上到右下的斜线上连续四个字符,从左上到右下构成 2020。
例如,对于下面的矩阵:
220000
000000
002202
000000
000022
002020
一共有 5 个 2020。其中 1 个是在同一行里的, 1 个是在同一列里的, 3 个
是斜线上的。
小蓝的矩阵比上面的矩阵要大,由于太大了,他只好将这个矩阵放在了一
个文件里面,在试题目录下有一个文件 2020.txt,里面给出了小蓝的矩阵。
请帮助小蓝确定在他的矩阵中有多少个 2020。

【答案提交】

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。


答案解析

答案是 16520。

打开 txt 文件,鼠标放到最后一行最后一列,可以知道,是一个300行300列的矩阵。然后直接暴力三次循环,分别是从左到右,从上到下,从左上到右下方向。比赛的时候在这里耗时有点久,因为调试的时候,发现我复制输入这个矩阵后,控制台输出的矩阵只有260多行,一直以为哪里写错了。

import java.util.Scanner;

public class Main{
     

    public static void main(String[] args) {
     
        // TODO Auto-generated method stub
        Scanner sc = new Scanner(System.in);
        int[][] num = new int[301][301];
        for (int i=1;i<=300;i++) {
     
            String str = sc.next();
            for (int j=1;j<=str.length();j++) {
     
                num[i][j] = str.charAt(j-1) - '0';
            }
        }
        
        int ans = 0;
        for (int i=1;i<=300;i++) {
     
            for (int j=1;j<=300;j++) {
     
                if (i+3<=300 && num[i][j]==2 && num[i+1][j]==0 && num[i+2][j]==2 && num[i+3][j]==0)
                    ans++;
            }
        }
        
        for (int i=1;i<=300;i++) {
     
            for (int j=1;j<=300;j++) {
     
                if (j+3<=300 && num[i][j]==2 && num[i][j+1]==0 && num[i][j+2]==2 && num[i][j+3]==0)
                    ans++;
            }
        }
        
        for (int i=1;i<=300;i++) {
     
            for (int j=1;j<=300;j++) {
     
                if (i+3<=300 && j+3<=300 && num[i][j]==2 && num[i+1][j+1]==0 && num[i+2][j+2]==2 && num[i+3][j+3]==0)
                    ans++;
            }
        }
        System.out.println(ans);

    }
}


试题 C: 蛇形填数(10分)

【问题描述】

如下图所示,小明用从 1 开始的正整数“蛇形”填充无限大的矩阵。

2020年第十一届蓝桥杯省赛第二场Java B组 总结_第1张图片

容易看出矩阵第二行第二列中的数是 5。请你计算矩阵中第 20 行第 20 列 的数是多少?

【答案提交】

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一 个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。


答案解析

答案是 761。

先说下我考试的思路吧,就是把整个矩阵想左转45°,然后就可以发现是一个有规律的三角形,可以发现矩阵中第 i 行第 j 列的数在这个三角形中是第 i* 2-1 行 j* 2-1 列最中间的数,那么第20行第20列就在三角形中的第39行39列的中间,答案也就出来了。

再说下别人的做法,直接找规律,第一行第一列的值为1,第二行第二列的值为5.第三行第三列的值为13,第四行第四列的值为25,仔细观察就可以发现第i行第i列的值为 a = a + (i*4)。可能要多画几个矩阵,才能发现规律。

public static void main(String[] args) {
     
	// TODO Auto-generated method stub
	int a = 1;
	for (int i = 0; i < 20; i++) {
     
		a = a + (i * 4);
		System.out.println(a);
	}
}


试题 D: 七段码(10分)

【问题描述】

小蓝要用七段码数码管来表示一种特殊的文字。

2020年第十一届蓝桥杯省赛第二场Java B组 总结_第2张图片
上图给出了七段码数码管的一个图示,数码管中一共有 7 段可以发光的二极管,分别标记为 a, b, c, d, e, f, g。

小蓝要选择一部分二极管(至少要有一个)发光来表达字符。在设计字符的表达时,要求所有发光的二极管是连成一片的。

  • 例如: b 发光,其他二极管不发光可以用来表达一种字符。

  • 例如: c 发光,其他二极管不发光可以用来表达一种字符。这种 方案与上 一行的方案可以用来表示不同的字符,尽管看上去比较相似。

  • 例如: a, b, c, d, e 发光, f, g 不发光可以用来表达一种字符。

  • 例如: b, f 发光,其他二极管不发光则不能用来表达一种字符,因为发光 的二极管没有连成一片。

请问,小蓝可以用七段码数码管表达多少种不同的字符?

【答案提交】

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。


答案解析



试题 E: 排序(15分)

【问题描述】

小蓝最近学习了一些排序算法,其中冒泡排序让他印象深刻。在冒泡排序中,每次只能交换相邻的两个元素。

小蓝发现,如果对一个字符串中的字符排序,只允许交换相邻的两个字符,则在所有可能的排序方案中,冒泡排序的总交换次数是最少的。
例如,对于字符串 lan 排序,只需要 1 次交换。对于字符串 qiao 排序,
总共需要 4 次交换。

小蓝找到了很多字符串试图排序,他恰巧碰到一个字符串,需要 100 次交
换,可是他忘了吧这个字符串记下来,现在找不到了。

请帮助小蓝找一个只包含小写英文字母且没有字母重复出现的字符串,对
该串的字符排序,正好需要 100 次交换。如果可能找到多个,请告诉小蓝最短的那个。如果最短的仍然有多个,请告诉小蓝字典序最小的那个。请注意字符串中不可以包含相同的字符。

【答案提交】

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个只包含小写英文字母的字符串,在提交答案时只填写这个字符串,填写多余的内容将无法得分。


答案解析

答案: jonmlkihgfedcba。

写个冒泡排序,计算交换次数,感觉主要还是考思维能力。首先要确定字符串的长度。当长度为4时,字符串为 zyxw ,交换次数为 6 ,可知字符串长度为 4 的最大交换次数s是 6,因为最左边的要移动到最右边,最右边的要移动到最左边。然后就不断地增加长度,测到 zyxwvutsrqponml时,最大交换次数为105。又因为要使得字典序最小,所以换w为 onmlkjihgfedcba。要使得次数减少 5 ,j 字母就要向左移 5 位,移到最左边,这样 onmlk 交换到最右边的时候次数分别减 1 ,所以交换次数就是 100。

public class Main {
     

    static int BubbleSort(String str) {
     
        int n = str.length();
        int[] a = new int[n+1];
        //先将字符串转换为int数组
        for (int i=1;i<=n;i++) {
     
            a[i] = str.charAt(i-1) - 'a' +1;
        }
        
        //26 25 24 23
        int count = 0;  //记录交换次数
        //冒泡排序
        for (int i = 1; i <= n - 1; i++) {
     
            for (int j = 1; j <= n - i; j++) {
     
                if (a[j] > a[j + 1]) {
     
                    count++;
                    int t = a[j];
                    a[j] = a[j + 1];
                    a[j + 1] = t;
                }
            }
        }
        
        //再转换为字符数组
        for (int i = 1; i <= n; i++) {
     
            System.out.print((char)(a[i]+'a'-1));
        }
        System.out.println();
        return count;
    }

    public static void main(String[] args) {
     
        // TODO Auto-generated method stub
        
        //测试,寻找字符串长度
        //zyxw 6
        //zyxwvutsrqponm 91
        //zyxwvutsrqponml 105  字符串长度为15
        //onmlkjihgfedcba 字典序要最小
        //jonmlkihgfedcba 100 
        System.out.println(BubbleSort("jonmlkihgfedcba"));;
    }

}


程序设计题


试题 F: 成绩分析(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。


答案解析

送分题,就是求数组最大数,最小数以及平均数。要注意的就是要四舍五入到小数点后两位的话就得用double型,double的除法 / 会自动四舍五入。

import java.util.Scanner;

public class Main{
     

    public static void main(String[] args) {
     
        // TODO Auto-generated method stub
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] num = new int[n+1];
        //因为是要精确,所以被除数和除数都要double型
        double sum = 0;
        for (int i=1;i<=n;i++) {
     
            num[i] = sc.nextInt();
            sum += num[i];
        }
        
        int maxx = num[1];
        int minn = num[1];
        for (int i=2;i<=n;i++) {
     
            maxx = Math.max(maxx, num[i]);
            minn = Math.min(minn, num[i]);
        }
        
        double ans = sum / n;
        System.out.println(maxx);
        System.out.println(minn);
        System.out.printf("%.2f",ans);

    }

}


试题 G: 单词分析 (20分)

【问题描述】

小蓝正在学习一门神奇的语言,这门语言中的单词都是由小写英文字母组 成,有些单词很长,远远超过正常英文单词的长度。小蓝学了很长时间也记不 住一些单词,他准备不再完全记忆这些单词,而是根据单词中哪个字母出现得 最多来分辨单词。

现在,请你帮助小蓝,给了一个单词后,帮助他找到出现最多的字母和这 个字母出现的次数。

【输入格式】

输入一行包含一个单词,单词只由小写英文字母组成。

【输出格式】

输出两行,第一行包含一个英文字母,表示单词中出现得最多的字母是哪 个。如果有多个字母出现的次数相等,输出字典序最小的那个。

第二行包含一个整数,表示出现得最多的那个字母在单词中出现的次数。

【样例输入】

lanqiao

【样例输出】

a
2

【样例输入】

longlonglongistoolong

【样例输出】

o
6

【评测用例规模与约定】

对于所有的评测用例,输入的单词长度不超过 1000。


答案解析

用一个数组从下标1到26分别表示26个字母,然后遍历字符串,记录每个字母出现的次数,然后再从字符串找出出现次数最多的那个数。

import java.util.Scanner;

public class Main {
     

    public static void main(String[] args) {
     
        // TODO Auto-generated method stub
        Scanner sc = new Scanner(System.in);
        int[] a = new int[30];
        String str = sc.next();
        int len = str.length();
        for (int i=0;i<len;i++) {
     
            a[str.charAt(i)-'a'+1]++;
        }
        int maxx = a[1];
        char ch = 'a';
        for (int i=2;i<=26;i++) {
     
            if (a[i] > maxx) {
     
                maxx = a[i];
                ch = (char) ('a' + i -1);
            }
        }
        System.out.println(ch);
        System.out.println(maxx);
    }
}


试题 H: 数字三角形(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


答案解析

典型的深搜题目,再加个判断条件使得向左下走的次数与向右下走的次数相差不能超过 1,注意回溯的时候次数要减 1 。

import java.util.Scanner;

public class Main {
     

    static int n;
    static int[][] dir = {
     {
     1,0},{
     1,1}};
    static int[][] num,vis;
    static int maxx;
    static void dfs(int x,int y,int left,int right,int sum) {
     
        if (x==n && Math.abs(left - right) <= 1) {
     
            maxx = Math.max(maxx, sum);
            return;
        }
        
        for (int i=0;i<2;i++) {
     
            int xx = x + dir[i][0];
            int yy = y + dir[i][1];
            if (xx>=1 && xx<=n && yy>=1 && yy<=xx && vis[xx][yy]==0) {
     
                vis[xx][yy] = 1;
                if (i==0)   left++;
                else    right++;
                dfs(xx,yy,left,right,sum+num[xx][yy]);
                vis[xx][yy] = 0;
                if (i==0)   left--;
                else    right--;
            }
        }
    }
    public static void main(String[] args) {
     
        // TODO Auto-generated method stub
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        num = new int[n+1][n+1];
        vis = new int[n+1][n+1];

        for (int i=1;i<=n;i++) {
     
            for (int j=1;j<=i;j++) {
     
                num[i][j] = sc.nextInt();
                vis[i][j] = 0;
            }
        }
        vis[1][1] = 1;
        maxx = num[1][1];
        dfs(1,1,0,0,num[1][1]);
        System.out.println(maxx);
    }
}


试题 I: 子串分值和(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。


答案解析

第一种做法:考试时来不及,就直接暴力解法,时间复杂度是O(n^3),应该可以过50%的样例。截取每一个子串,然后写一个函数计算字符串还有最大的不同字符个数。

第二种做法:用两层循环,把子串都取出来,然后把所有字符都切割出来,用HashSet存入,因为有自动去重功能,它的长度就是不同字符的个数。


import java.util.Scanner;

public class Main {
     

    static long ans = 0;
    //计算字符串里里面不同字符的个数
    static int culcate(String str) {
     
        int ans = 0;
        int[] a = new int[30];
        for (int i=1;i<=26;i++) {
     
            a[i] = 0;
        }
        for (int i=0;i<str.length();i++) {
     
            a[str.charAt(i)-'a'+1] = 1;
        }
        for (int i=1;i<=26;i++) {
     
            ans += a[i];
        }
        return ans;
    }
    public static void main(String[] args) {
     
        // TODO Auto-generated method stub
        Scanner sc = new Scanner(System.in);
        String str = sc.next();
        int len = str.length();
        for (int i=0;i<len;i++) {
     
            for (int j=i+1;j<=len;j++) {
     
                ans += culcate(str.substring(i, j));
            }
        }
        System.out.println(ans);
    }

}

你可能感兴趣的:(蓝桥杯)