2020年第十一届蓝桥杯Java B组省赛第二场个人题解

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

1.门牌制作——答案:624

2020年第十一届蓝桥杯Java B组省赛第二场个人题解_第1张图片
思路: 暴力,遍历1-2020,先把每个数字转成字符数组,再统计数组中的字符,累加
代码:

public class A门牌制作 {
     

		/**
	 * @param args
	 * 暴力,从1-2020,先把每个数字转成字符数组,再统计数组中的字符,累加
	 */
	public static void main(String[] args) {
     
		// TODO Auto-generated method stub
		int sum = 0 ;
		char [] ch;
		for (int i = 1; i <=2020; i++) {
     
			ch = Integer.toString(i).toCharArray();
			for (int j = 0; j < ch.length; j++) {
     
				if (ch[j] =='2') {
     
					sum++;
				}
			}
		}
		System.out.println(sum);//624
	}

}

2.寻找2020——答案:16520

2020年第十一届蓝桥杯Java B组省赛第二场个人题解_第2张图片
代码:


import java.util.Scanner;

public class B寻找2020 {
     

	/**
	 * @param args
	 */
	public static void main(String[] args) {
     
		// TODO Auto-generated method stub
		Scanner scanner = new Scanner(System.in);
		char[][] ch = new char[300][300];
		long sum = 0 ;
		for (int i = 0; i < ch.length; i++) {
     
			ch[i] = scanner.nextLine().toCharArray();
		}
		for (int i = 0; i < ch.length; i++) {
     
			for (int j = 0; j < ch[0].length; j++) {
     
				if (j+3<ch[0].length) {
     
					if (ch[i][j]=='2' && ch[i][j+1]=='0' &&ch[i][j+2]=='2' &&ch[i][j+3]=='0' ) {
     
						sum++;
					}
				}
				if (i+3<ch.length) {
     
					if (ch[i][j]=='2' && ch[i+1][j]=='0' &&ch[i+2][j]=='2' &&ch[i+3][j]=='0') {
     
						sum++;
					}
				}
				if (i+3<ch.length && j+3<ch[0].length) {
     
					if (ch[i][j]=='2' && ch[i+1][j+1]=='0' &&ch[i+2][j+2]=='2' &&ch[i+3][j+3]=='0') {
     
						sum++;
					}
				}
			}
		}
		System.out.println(sum);//16520
	}

}

3.蛇形填图——答案:761

2020年第十一届蓝桥杯Java B组省赛第二场个人题解_第3张图片
找规律:
第一行第一列是1;
第二行第二列是前面两条斜行(左上到右下或者右上到左下为一条斜行),再数两个数。
第三行第三列是前面四条斜行,再数三个数。
依次类推,20行第20列是前面38条斜行,再数20个数。
38条斜行为:1+2+…+38,最后结果(1+2+…+38)+20 = (1+38)38/2 +20 = 3919+20 = 761

4. 七段码——答案:80

2020年第十一届蓝桥杯Java B组省赛第二场个人题解_第4张图片

思路: 本题的大致思路是

  1. 将数码管的七段进行全排列(用数字代表数码管字段,0代表a,1代表b,以此类推)然后将这7个数字的所有可能全部排列(从7个数字中取m(1<=m<=7)进行排列)列举出来。
  2. 得到所有的取值情况,再判断每种情况构成的图是否连通,若连通,sum++
  3. 进行排列时需要注意,一定要保证每个排列必须是递增或者递减,这样才能不重复,例如:012,021,210等等,它们都表示数码管中取出ABC这一种情况。
    代码:
package 第二场;

public class D七段码 {
     

	/**
	 * @param args
	 * 本题的大致思路是将数码管的七段进行全排列(用数字代表数码管字段,0代表a,1代表b,以此类推)然后将这7个数字的所有可能全部排列(从7个数字中取m(1<=m<=7)进行排列)列举出来
	 * 得到所有的取值情况,再判断每种情况构成的图是否连通,若连通,sum++
	 * 进行排列时需要注意,一定要保证每个排列必须是递增或者递减,这样才能不重复,例如:012,021,210等等,它们都表示数码管中取出ABC这一种情况
	 */
	static boolean [][] M ;//M是邻接矩阵
	static int []a;//a代表排列组合的数字
	static int sum = 0 ;//最后结果
	public static void main(String[] args) {
     
		// TODO Auto-generated method stub
		/*M是邻接矩阵,根据数码管图像可以得到
		 * 例如:a和b,a和f都可以连通,那么代表0和1,0和5连通
		*/
		M = new boolean[7][7] ;
		M[0][1] = M[1][0] = M[0][5] = M[5][0] = true;
		M[1][2] = M[2][1] = M[1][6] = M[6][1] = true;
		M[2][3] = M[3][2] = M[2][6] = M[6][2] = true;
		M[4][3] = M[3][4] = true;
		M[4][5] = M[5][4] = M[4][6] = M[6][4] = true;
		M[5][6] = M[6][5] = true;
		a = new int [7];
		for (int i = 0; i < a.length; i++) {
     
			a[i] = i;
		}
		//所有排列的可能,深搜
		for(int n = 1;n <=7;n++){
     
			dfs(0, n);
		}
		System.out.println(sum);
		
	}
	public static void  dfs(int k,int n) {
     
		if (k == n) {
     
			//如果只有一个数,那么这种情况下必然成立
			if (n == 1) {
     
				sum++;
				return;
			}
			//判断,这种情况下的图是否连通。用的是并查集方法
			//初始化
			int []pre = new int[n];
			for (int i = 0; i < pre.length; i++) {
     
				pre[i]  =  i ;
			}
			for (int i = 0; i <n; i++) {
     
				for(int j = i+1;j<n;j++){
     
					//两层for穷举所有边的情况
					//若i和j连通,j加入i
					//i和j代表的是结点,所以并的时候就是jion(pre, i,j)。但是i代表的结点好j代表的结点是否连通,则需要看a[i]]和[a[j]在邻接矩阵M中是否为真
					if (M[a[i]][a[j]]) {
     
						jion(pre, i,j);
					}
				}
			}
			//到最后,若所有结点都连通,则所有结点的跟结点应该都一样。否则说明此情况下的图不连通
			boolean flag = true;
			for (int i = 1; i <pre.length; i++) {
     
				if ( find(pre, 0)!= find(pre, i) ) {
     
					flag = false;
					break;
				}
			}
			if (flag) {
     
				sum++;
			}
			return;
		}
		//dfs,深搜
		for (int i = k; i < a.length; i++) {
     
			if (k == 0 || a[i]>a[k-1]) {
     
				int t = a[i];
				a[i] = a[k];
				a[k] = t;
				dfs(k+1, n);
				t = a[i];
				a[i] = a[k];
				a[k] = t;
			}
		}
	}
	//查找根节点
	public static int find(int[] pre,int node) {
     
		int son = node,temp = 0;
		//查找根节点
		while(node != pre[node]){
     
			node = pre[node];
		}
		//路径优化
		while(son != node){
     
			temp = pre[son];
			//直接通跟
			pre[son] = node;
			//son向上走一格
			son = pre[son];	
		}
		return node;
    }
	//两个结点相并
	public static void jion (int[] pre,int x,int y) {
     
		int fx=find(pre,x);
		int fy=find(pre,y);
		//两个结点属于不同图,相并
		if(fx!=fy){
     
			pre[fy]=fx;
		}
			
	}
}

5.排序

2020年第十一届蓝桥杯Java B组省赛第二场个人题解_第5张图片
思路: 首先要注意最后得到的字符串全是英文小写字母并且不重复。接下来进行分析,最后要求结果在最短的前提下字典序最小。那么我们先想办法找到最短的结果。
  最短,那是能多短就多短。最短是长度是1,但是肯定不可能,因为他还要求字符串进行了100次交换,那么长度为2可不可以呢?也不行,长度为2的字符串最多进行一次交换。
  一个长度为n的字符串,如果进行冒泡排序,假设他每次比较都进行了交换,那么它最多交换 (n-1)+(n-2)+…+1 = n*(n-1)/2 (进行n-1趟操作,第一趟操作交换n-1次,之后每趟交换的次数依次递减)。
  在n*(n-1)/2>=100的前提下,n的最小值是15。也就是说,最后结果的字符串的长度至少15(低于15,它根本连交换100次的要求都达不到)。接下来再和题目要求的字典序最小一起考虑。
  首先了解一下字典序:字典序是指从前到后比较两个字符串的大小的方法。首先比较第一个字符,如果不同则第一个字符较小的字符串更小,如果相同则继续比较第2个字符…如此继续,来比较整个字符串的大小。
  现在我们知道字符串全是英文小写字母,并且长度为15且各不相同,那么我们可以确定这15个字母就是前15个小写英文字母abcdefghijklklmno,怎么排现在还不知道。
  用逆向思维思考,若这15个字母每次冒泡两两比较都进行交换,能交换 15*(15-1) = 105次,那这个字符串只可能是这15个字母的逆序:onmlkjighfedecba。
  然后我们再想办法减少逆序字符串的5次比较,并且使最后得到的结果字典序最小,只需要把逆序字符串的第六位提前至第一位:jonmlkighfedecba。在这种情况下,字典序就是最小的,我只需要第一位比你小,我就是字典序最小的。而且第1,2,3,4,5趟,每次j会分别和o,n,m,k,l进行比较,但是不交换,这样就省下了5次交换,且最后一共交换105-5=100次。
最后结果为:jonmlkighfedecba
第五题是本人个人思路,不能确保答案一定正确,若有不同想法和答案,欢迎评论区讨论

6. 成绩分析

时间限制: 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 F成绩分析 {
     

	/**
	 * @param args
	 */
	public static void main(String[] args) {
     
		// TODO Auto-generated method stub
		Scanner scanner = new Scanner(System.in);
		int n = 0,t=0,max=Integer.MIN_VALUE,min=Integer.MAX_VALUE;
		double sum = 0;
		n = scanner.nextInt();
		for (int i = 0; i < n; i++) {
     
			t = scanner.nextInt();
			sum+= t;
			if (t>max) {
     
				max = t;
			}
			if (t<min) {
     
				min = t;
			}
		}
		System.out.println(max);
		System.out.println(min);
		System.out.println(String.format("%.2f", sum/n));
	}
}

7.单词分析

时间限制: 1.0s

内存限制: 512.0MB

本题总分:20 分

【问题描述】
小蓝正在学习一门神奇的语言,这门语言中的单词都是由小写英文字母组
成,有些单词很长,远远超过正常英文单词的长度。小蓝学了很长时间也记不
住一些单词,他准备不再完全记忆这些单词,而是根据单词中哪个字母出现得
最多来分辨单词。
现在,请你帮助小蓝,给了一个单词后,帮助他找到出现最多的字母和这
个字母出现的次数。

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

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

【样例输入】

lanqiao

【样例输出】

a
2

【样例输入】

longlonglongistoolong

【样例输出】

o
6

【评测用例规模与约定】

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


import java.util.Scanner;

public class G单词分析 {
     

	/**
	 * @param args
	 */
	public static void main(String[] args) {
     
		// TODO Auto-generated method stub
		Scanner scanner = new Scanner(System.in);
		char[] ch = scanner.nextLine().toCharArray();
		int[] num = new int[26];
		for (int i = 0; i < ch.length; i++) {
     
			num[ch[i]-'a']++;
		}
		int max = Integer.MIN_VALUE;
		char maxChar = 0 ;
		for (int i = 0; i < num.length; i++) {
     
			if (num[i] > max) {
     
				max = num[i];
				maxChar = (char) ('a' + i) ;
			}
		}
		System.out.println(maxChar+"\n"+max);
	}

}

8.数字三角形

时间限制: 1.0s

【问题描述】

内存限制: 512.0MB

本题总分:20 分
2020年第十一届蓝桥杯Java B组省赛第二场个人题解_第6张图片
上图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。
对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最
大的和。
路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右
边的那个数。此外,向左下走的次数与向右下走的次数相差不能超过 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

9.子串分值和

时间限制: 1.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

【样例说明】
2020年第十一届蓝桥杯Java B组省赛第二场个人题解_第7张图片
在这里插入图片描述

【评测用例规模与约定】

对于 20% 的评测用例,1 ≤ n ≤ 10;
对于 40% 的评测用例,1 ≤ n ≤ 100;
对于 50% 的评测用例,1 ≤ n ≤ 1000;
对于 60% 的评测用例,1 ≤ n ≤ 10000;
对于所有评测用例,1 ≤ n ≤ 100000。
代码:

package 第二场;

import java.util.Scanner;

public class I子串分值和 {
     

	/**
	 * @param args
	 * 暴力穷举
	 */
	public static void main(String[] args) {
     
		// TODO Auto-generated method stub
		Scanner s = new Scanner(System.in);
	    String s1 = s.nextLine();
	    char[]  a = s1.toCharArray();
	    int sum = 0, preSum = 0 ;
	    int []num = new int [26];
	    //二进制形式下,最后一位置位1,其他为0,代表a,倒数第二位置为1,其他置为0代表b,以此类推。
	    for (int i = 0; i < num.length; i++) {
     
			num[i] = 1<<i;
		}
	    
	    //穷举子串i-j的不同字符数
	    int temp = 0 ;//temp的代表意思是子串的字符占位情况
	    //例如子串为abcbba,一共有三个字符,abc,那么它的占位情况是111(2);
	    for (int i = 0; i < a.length; i++) {
     
	    	temp = 0 ;
	    	preSum = 0;
	        for (int j = i; j < a.length; j++) {
     
	        	if (i == j) {
     //子串长度为1,子串的不同字符数为1
	        		temp = num[a[j]-'a'] ;//字符占位
	        		preSum = 1; 
					
				}else {
     
					//temp|num[a[j]-'a'] 的结果是:将 a[j]代表的字符占位到temp中,
					//如果第j位字符占位之后的temp和原来的temp相等,
					//说明第j位字符早已占位,那么当前子串i-j和上一个子串i-(j-1)的不同字符相同,preSum不变
					//否则,preSum++;
					if ((temp|num[a[j]-'a']) != temp){
     
					    temp = 	temp|num[a[j]-'a'];
					    preSum++;
					}
				}
	        	sum += preSum ;
	        }
	    }
//	    for (int i = 0; i < res.length; i++) {
     
//			for (int j = 0; j < res.length; j++) {
     
//				System.out.print(res[i][j]+ "  ");
//			}
//			System.out.println();
//		}
	    System.out.println(sum);
	}

}

未完待续。如果发现错误,请各位阅读者评论指出,不胜感激

你可能感兴趣的:(蓝桥杯省赛JavaB组,java)