2020蓝桥杯省赛第二场C组_java

2020蓝桥杯省赛第二场C组

  • 试题 A: 约数个数
    • 【问题描述】
    • 【题解】
  • 试题 B: 寻找 2020
    • 【问题描述】
    • 【题解】
  • 试题 C: 跑步锻炼
    • 【问题描述】
    • 【题解】
  • 试题 D: 平面分割
    • 【问题描述】
    • 【题解】
  • 试题 E: 七段码
    • 【问题描述】
    • 【题解】
  • 试题 F: 成绩统计
    • 【问题描述】
    • 【题解】
  • 试题 G: 单词分析
    • 【问题描述】
    • 【题解】
  • 试题 H: 数字三角形
    • 【问题描述】
    • 【题解】
  • 试题 I: 作物杂交
    • 【问题描述】
    • 【题解】
  • 试题 J: 子串分值
    • 【问题描述】
    • 【题解】

试题 A: 约数个数

本题总分:5 分

【问题描述】

对于一个整数,能整除这个整数的数称为这个数的约数。
例如:1, 2, 3, 6 都是 6 的约数。
请问 78120 有多少个约数。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

【题解】

答案 :96
遍历一遍所有小于等于78120的数得了

public class Main {
    public static void main(String[] args) {
        int cut = 0;
        for (int i = 1; i <= 78120; i++) {
            if (78120 % i == 0) cut ++;
        }
        System.out.println(cut);
    }
}

2020蓝桥杯省赛第二场C组_java_第1张图片

试题 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

import java.io.BufferedReader;
import java.io.FileReader;

public class Main {
    public static void main(String[] args) throws Exception {
        //缓冲流读入文件,后面路径看你放在哪个位置了
        BufferedReader br = new BufferedReader(new FileReader("src/2020.txt"));
        String s = null;
        char[][] a = new char[300][];
        int in = 0;
        while ((s = br.readLine()) != null) {
            a[in] = s.toCharArray();
            in ++;
        }
        //定义方向,右,下,右下
        int[][] dir = {{0, 1}, {1, 0}, {1, 1}};
        //cut存储2020个数
        int cut = 0;
        for (int i = 0; i < a.length; i++) {
            for (int j = 0; j < a[i].length; j++) {
                if (a[i][j] != '2') continue;
                for (int k = 0; k < dir.length; k++) {
                    //向三个方向延伸
                    int temp = 2;
                    int x = i, y = j;
                    for (int l = 0; l < 3; l++) {
                        x += dir[k][0];
                        y += dir[k][1];
                        //处理一下边界
                        if (x >= a.length || y >= a[x].length) break;
                        //拼接数字
                        temp = temp * 10 + a[x][y] - '0';
                    }
                    //计算出每个方向的值比对
                    if (temp == 2020) {
                        cut ++;
                    }
                }
            }
        }
        System.out.println(cut);
    }
}

2020蓝桥杯省赛第二场C组_java_第2张图片

试题 C: 跑步锻炼

本题总分:10 分

【问题描述】

小蓝每天都锻炼身体。
正常情况下,小蓝每天跑 1 千米。如果某天是周一或者月初(1 日),为了激励自己,小蓝要跑 2 千米。如果同时是周一或月初,小蓝也是跑 2 千米。
小蓝跑步已经坚持了很长时间,从 2000 年 1 月 1 日周六(含)到 2020 年10 月 1 日周四(含)。请问这段时间小蓝总共跑步多少千米?
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

【题解】

答案:8879

public class Main {
    public static void main(String[] args) {
        int[] week = {1,2,3,4,5,6,7};
        int weeki = 5;
        int[] date = {2000,0,0};    //为了方便处理,月份和日都从0开始
        int sum = 0;        //存储这20年跑步的总和
        while (true) {
            int year = date[0];
            int month = date[1];
            int day = date[2];
            //打印日期,测试日期是否进入正轨
            System.out.println(year+"年"+(month+1)+"月"+(day+1)+"日");
            int s = 1;
            if (week[weeki] == 1 || day == 0) {
                s = 2;
            }
            sum += s;
            if (year == 2020 && month == 9 && day == 0) {
                break;
            }
            weeki = (weeki + 1) % 7;
            //对于月份和日份构成循环
            date[2] = (day + 1) % getDayOfMonth(year,month);
            date[1] = (month + (day + 1) / getDayOfMonth(year,month)) % 12;
            //月份由12月变成1月时年份+1
            if (month == 11 && date[1] == 0) date[0] ++;
        }
        System.out.println(sum);
    }
    private static int getDayOfMonth(int year,int month) {
        switch (month) {
            case 0:
            case 2:
            case 4:
            case 6:
            case 7:
            case 9:
            case 11:
                return 31;
            case 3:
            case 5:
            case 8:
            case 10:
                return 30;
            case 1:
                if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
                    return 29;
                }
                return 28;
        }
        return 0;
    }
}

2020蓝桥杯省赛第二场C组_java_第3张图片

试题 D: 平面分割

本题总分:10 分

【问题描述】

20 个圆和 20 条直线最多能把平面分成多少个部分?
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

【题解】

试题 E: 七段码

本题总分:15 分

【问题描述】

小蓝要用七段码数码管来表示一种特殊的文字。
2020蓝桥杯省赛第二场C组_java_第4张图片

上图给出了七段码数码管的一个图示,数码管中一共有 7 段可以发光的二极管,分别标记为 a, b, c, d, e, f, g。
小蓝要选择一部分二极管(至少要有一个)发光来表达字符。在设计字符的表达时,要求所有发光的二极管是连成一片的。

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

一行的方案可以用来表示不同的字符,尽管看上去比较相似。

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

请问,小蓝可以用七段码数码管表达多少种不同的字符?
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

【题解】

答案:80
2020蓝桥杯省赛第二场C组_java_第5张图片

import java.util.ArrayList;
import java.util.HashSet;

public class Main {
    //res存储灯管显示方式
    static HashSet<HashSet<Character>> res = new HashSet<>();
    public static void main(String[] args) {
        //存储所有灯管的连接关系
        ArrayList<G> list = new ArrayList<>();
        list.add(new G('a', 'b'));
        list.add(new G('a', 'f'));
        list.add(new G('c', 'b'));
        list.add(new G('g', 'b'));
        list.add(new G('c', 'd'));
        list.add(new G('c', 'g'));
        list.add(new G('e', 'd'));
        list.add(new G('e', 'g'));
        list.add(new G('e', 'f'));
        list.add(new G('f', 'g'));
        dfs(list,new ArrayList<G>(),0);
        //结果加上7,是因为有七种方式只有一个灯管,不与其他灯管相连
        System.out.println(res.size() + 7);
    }
    /*
    深搜所有灯管连接的子集
     */
    private static void dfs(ArrayList<G> list, ArrayList<G> gs, int i) {
        if (i == list.size()) {
            HashSet<Character> ds = new HashSet<>();
            //ds获得gs里面所有的灯管
            for (int j = 0; j < gs.size(); j++) {
                ds.add(gs.get(j).start);
                ds.add(gs.get(j).end);
            }
            //当灯管的数量比连接的数量多1,表示所有的灯管连在一起
            if (ds.size() - 1 == gs.size()) {
                res.add(ds);
            }
            return;
        }
        dfs(list, gs, i + 1);
        gs.add(list.get(i));
        dfs(list, gs, i + 1);
        gs.remove(list.get(i));
    }
}
/*
类名懒得想,就这样写个G吧
该类表示哪两个灯管连着
 */
class G {
    char start;
    char end;
    public G (char start, char end) {
        this.start = start;
        this.end = end;
    }
}

2020蓝桥杯省赛第二场C组_java_第6张图片

试题 F: 成绩统计

时间限制: 1.0s 内存限制: 512.0MB
本题总分:15 分

【问题描述】

小蓝给学生们组织了一场考试,卷面总分为 100 分,每个学生的得分都是一个 0 到 100 的整数。
如果得分至少是 60 分,则称为及格。如果得分至少为 85 分,则称为优秀。
请计算及格率和优秀率,用百分数表示,百分号前的部分四舍五入保留整数。
【输入格式】
输入的第一行包含一个整数 n,表示考试人数。
接下来 n 行,每行包含一个 0 至 100 的整数,表示一个学生的得分。
【输出格式】
输出两行,每行一个百分数,分别表示及格率和优秀率。百分号前的部分四舍五入保留整数。
【样例输入】

7
80
92
56
74
88
100
0

【样例输出】

71%
43%

【评测用例规模与约定】
对于 50% 的评测用例,1 ≤ n ≤ 100。
对于所有评测用例,1 ≤ n ≤ 10000。

【题解】

import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		double k = 0,l = 0;	//k统计及格率,l统计优秀率
		for (int i = 0; i < n; i++) {
			int s = sc.nextInt();
			if (s >= 60) k ++;
			if (s >= 85) l ++;
		}
		//求百分比并四舍五入
		k = k / n * 100 + 0.5;
		l = l / n * 100 + 0.5;
		System.out.println((int)k + "%");
		System.out.println((int)l + "%");
	}
}

2020蓝桥杯省赛第二场C组_java_第7张图片

试题 G: 单词分析

时间限制: 1.0s 内存限制: 512.0MB
本题总分:20 分

【问题描述】

小蓝正在学习一门神奇的语言,这门语言中的单词都是由小写英文字母组成,有些单词很长,远远超过正常英文单词的长度。小蓝学了很长时间也记不住一些单词,他准备不再完全记忆这些单词,而是根据单词中哪个字母出现得最多来分辨单词。
现在,请你帮助小蓝,给了一个单词后,帮助他找到出现最多的字母和这个字母出现的次数。
【输入格式】
输入一行包含一个单词,单词只由小写英文字母组成。
【输出格式】
输出两行,第一行包含一个英文字母,表示单词中出现得最多的字母是哪个。如果有多个字母出现的次数相等,输出字典序最小的那个。
第二行包含一个整数,表示出现得最多的那个字母在单词中出现的次数。
【样例输入】

lanqiao

【样例输出】

a
2

【样例输入】

longlonglongistoolong

【样例输出】

o
6

【评测用例规模与约定】
对于所有的评测用例,输入的单词长度不超过 1000。

【题解】

import java.util.HashMap;
import java.util.Iterator;
import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		String s = sc.next();
		sc.close();
		//计算各个字母数量
		HashMap<Character, Integer> map = new HashMap<Character, Integer>();
		for (char c : s.toCharArray()) {
			map.put(c, map.getOrDefault(c, 0) + 1);
		}
		//找出最多的字母
		char res = 'a';
		Iterator<Character> it = map.keySet().iterator();
		while (it.hasNext()) {
			char c = it.next();
			if (map.get(c) > map.getOrDefault(res, 0)) {
				res = c;
			}
		}
		System.out.println(res);
		System.out.println(map.get(res));
	}
}

2020蓝桥杯省赛第二场C组_java_第8张图片
2020蓝桥杯省赛第二场C组_java_第9张图片

试题 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.util.Scanner;

public class Main {
	static int n;	//三角形行数
	static int[][] a;	//存储三角形
	static int max;	//存储路径和最大值
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		a = new int[n][];
		for (int i = 0; i < n; i++) {
			a[i] = new int[i + 1];
			for (int j = 0; j <= i; j++) {
				a[i][j] = sc.nextInt();
			}
		}
		//先算出左右各拐多少次
		int l = (n - 1) / 2;
		int r = n - 1 - l;
		//深搜所有可走路线计算路径和
		dfs(l,r,0,0,a[0][0]);
		//如果l和r不相等,就换一下再搜一遍
		if (l != r) {
			dfs(r, l, 0, 0, a[0][0]);
		}
		System.out.println(max);
	}
	private static void dfs(int l, int r, int i, int j,int sum) {
		//左右次数都用完,结束递归
		if (l == 0 && r == 0) {
			if (sum > max) {
				max = sum;
			}
		}
		//左拐次数大于0才能向左走
		if (l > 0) {
			dfs(l - 1, r, i + 1, j, sum + a[i + 1][j]);
		}
		//右拐次数大于0,才能向右走
		if (r > 0) {
			dfs(l, r - 1, i + 1, j + 1, sum + a[i + 1][j + 1]);
		}
	}
}

2020蓝桥杯省赛第二场C组_java_第10张图片

试题 I: 作物杂交

时间限制: 1.0s 内存限制: 512.0MB
本题总分:25 分

【问题描述】

作物杂交是作物栽培中重要的一步。已知有 N 种作物 (编号 1 至 N ),第i 种作物从播种到成熟的时间为 Ti。作物之间两两可以进行杂交,杂交时间取两种中时间较长的一方。如作物 A 种植时间为 5 天,作物 B 种植时间为 7 天,则 AB 杂交花费的时间为 7 天。作物杂交会产生固定的作物,新产生的作物仍然属于 N 种作物中的一种。
初始时,拥有其中 M 种作物的种子 (数量无限,可以支持多次杂交)。同时可以进行多个杂交过程。求问对于给定的目标种子,最少需要多少天能够得到。
如存在 4 种作物 ABCD,各自的成熟时间为 5 天、7 天、3 天、8 天。初始拥有 AB 两种作物的种子,目标种子为 D,已知杂交情况为 A × B → C,
A × C → D。则最短的杂交过程为:

  • 第 1 天到第 7 天 (作物 B 的时间),A × B → C。
  • 第 8 天到第 12 天 (作物 A 的时间),A × C → D。

花费 12 天得到作物 D 的种子。
【输入格式】
输入的第 1 行包含 4 个整数 N, M, K, T,N 表示作物种类总数 (编号 1 至N),M 表示初始拥有的作物种子类型数量,K 表示可以杂交的方案数,T 表示目标种子的编号。
第 2 行包含 N 个整数,其中第 i 个整数表示第 i 种作物的种植时间Ti(1 ≤ Ti ≤ 100)。
第 3 行包含 M 个整数,分别表示已拥有的种子类型 Kj(1 ≤ Kj ≤ M),Kj两两不同。
第 4 至 K + 3 行,每行包含 3 个整数 A, B,C,表示第 A 类作物和第 B 类作物杂交可以获得第 C 类作物的种子。
【输出格式】
输出一个整数,表示得到目标种子的最短杂交时间。
【样例输入】

6 2 4 6
5 3 4 6 4 9
1 2
1 2 3
1 3 4
2 3 5
4 5 6

【样例输出】

16

【样例说明】

  • 第 1 天至第 5 天,将编号 1 与编号 2 的作物杂交,得到编号 3 的作物种子。
  • 第 6 天至第 10 天,将编号 1 与编号 3 的作物杂交,得到编号 4 的作物种子。
  • 第 6 天至第 9 天,将编号 2 与编号 3 的作物杂交,得到编号 5 的作物种子。
  • 第 11 天至第 16 天,将编号 4 与编号 5 的作物杂交,得到编号 6 的作物种子。

总共花费 16 天。
【评测用例规模与约定】
对于所有评测用例,1 ≤ N ≤ 2000, 2 ≤ M ≤ N, 1 ≤ K ≤ 100000, 1 ≤ T ≤ N,保证目标种子一定可以通过杂交得到。

【题解】

import java.util.HashMap;
import java.util.Scanner;

public class Main {
	static int n,m,k,t;
	static int[] ti;	//存储各种子成熟时间
	static boolean[] hi;	//存储是否已经拥有该种子
	
	//存储某个种子是由哪两个种子杂交而成
	static HashMap<Integer, int[]> map = new HashMap<Integer, int[]>();	
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		m = sc.nextInt();
		k = sc.nextInt();
		t = sc.nextInt();
		ti = new int[n];
		hi = new boolean[n];
		for (int i = 0; i < n; i++) {
			ti[i] = sc.nextInt();
		}
		for (int i = 0; i < m; i++) {
			hi[sc.nextInt() - 1] = true;
		}
		for (int i = 0; i < k; i++) {
			int a = sc.nextInt(),
				b = sc.nextInt(),
				c = sc.nextInt();
			map.put(c, new int[]{a,b});
		}
		int res = dfs(t);
		System.out.println(res);
	}
	/*
	该方法计算拿到种子t所需时间
	*/
	private static int dfs(int t) {
		//如果种子t存在,就返回0
		if (hi[t - 1]) {
			return 0;
		}
		//改变一下种子状态,设为已存在
		hi[t - 1] = true;
		//没有这个种子
		//计算获得能够杂交出种子t的种子a和b的时间
		int ai = dfs(map.get(t)[0]);
		int bi = dfs(map.get(t)[1]);
		//计算杂交出种子t的时间
		int at = ti[map.get(t)[0] - 1];
		int bt = ti[map.get(t)[1] - 1];
		//由于获得种子a和b可以同时进行,取耗费时间最大值
		//题上说杂交时间取最大值
		return Math.max(ai, bi) + Math.max(at,bt);
	}
}

2020蓝桥杯省赛第二场C组_java_第11张图片

试题 J: 子串分值

时间限制: 1.0s 内存限制: 512.0MB
本题总分:25 分

【问题描述】

对于一个字符串 S,我们定义 S 的分值 f(S ) 为 S 中恰好出现一次的字符个数。例如 f(”aba”) = 1,f(”abc”) = 3, f(”aaa”) = 0。
现在给定一个字符串 S [0…n - 1](长度为 n),请你计算对于所有 S 的非空子串 S [i… j] (0 ≤ i ≤ j < n),f(S [i… j]) 的和是多少。
【输入格式】
输入一行包含一个由小写字母组成的字符串 S。
【输出格式】
输出一个整数表示答案。
【样例输入】

ababc

【样例输出】

21

【样例说明】

子串 	f值
a		1
ab		2
aba 	1
abab 	0
ababc 	1
b 		1
ba 		2
bab 	1
babc 	2
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.HashMap;
import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		String s = sc.next();
		sc.close();
		int n = s.length();
		int sum = n;	//sum存储最终结果
		for (int i = 0; i < n; i++) {
			//哈希存储子串中各字符的个数
			HashMap<Character, Integer> map = new HashMap<Character, Integer>();
			map.put(s.charAt(i), 1);
			int cut = 1;	//cut存储当前子串单字符的个数
			for (int j = i + 1; j < n; j++) {
				char c = s.charAt(j);
				int count = map.getOrDefault(c, 0);
				//拿到一个字符,如果这个字符是前面没出现过的,代表当前子串多了一个恰好出现一次的字符
				//如果前面这个字符有一个该字符,则当前子串少了一个恰好出现一次的字符
				if (count == 0) {
					cut ++;
				} else if (count == 1) {
					//cut最小为0,不要减到负数了
					cut = Math.max(cut - 1, 0);
				}
				//将字符加入哈希
				map.put(c, count+1);
				//将当前子串的恰好出现一次的字符的个数加入结果
				sum += cut;
			}
		}
		System.out.println(sum);
	}
}

2020蓝桥杯省赛第二场C组_java_第12张图片

你可能感兴趣的:(蓝桥杯,java,字符串,算法,dfs)