最新最全第十届蓝桥杯解析(Java)

A 组队

作为篮球队教练,你需要从以下名单中选出 1 号位至 5 号位各一名球员,组成球队的首发阵容。

每位球员担任 1 号位至 5 号位时的评分如下表所示。

请你计算首发阵容 1号位至 5 号位的评分之和最大可能是多少?

1 97 90 0 0 0
2 92 85 96 0 0
3 0 0 0 0 93
4 0 0 0 80 86
5 89 83 97 0 0
6 82 86 0 0 0
7 0 0 0 87 90
8 0 97 96 0 0
9 0 0 89 0 0
10 95 99 0 0 0
11 0 0 96 97 0
12 0 0 0 93 98
13 94 91  0 0 0
14 0 83 87 0 0
15 0 0 98 97 98
16 0 0 0 93 86
17 98 83 99 98 81
18 93 87 92 96 98
19 0 0 0 89 92
20 0 99 96 95 81

解析

采用 DFS 枚举每个位置运动员编号

注意第一列是编号,可以把文本复制粘贴到word里,然后按住Alt + shift就可以删除第一列了

代码

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class Main {
    
    
	static int[][] a = new int[25][10];
	static boolean[] vis = new boolean[25];
	static int max = Integer.MIN_VALUE; // Integer.MIN_VALUE 代表Integer的最小值-2147483648

	public static void main(String[] args) throws FileNotFoundException {
    
    
		// TODO Auto-generated method stub
		Scanner inScanner = new Scanner(new File("src/data.txt")); // 读取data.txt的内容
		for (int i = 0; i < 20; i++)
			for (int j = 0; j < 5; j++) {
    
    
				a[i][j] = inScanner.nextInt(); // 存入数组
			}
		DFS(0, 0);
		System.out.println(max);
	}

	static void DFS(int count, int sum) {
    
     // count记录选择的人数,最终只能5人,sum表示当前的权值
		if (count == 5) {
    
     // 选择出了5人
			if (sum > max) {
    
    
				max = sum; // 得到更大的sum权值,更新
			}
			return;
		}
		for (int i = 0; i < 20; i++) {
    
    
			if (!vis[i]) {
    
     // 当前号的运动员尚未选择
				vis[i] = true; // 标记当前运动员已选择
				DFS(count + 1, sum + a[i][count]);
				vis[i] = false; // 回溯
			}
		}

	}

}

B 不同字串

一个字符串的非空子串是指字符串中长度至少为 1 的连续的一段字符组成的串。

例如,字符串aaab 有非空子串a, b, aa, ab, aaa, aab, aaab,一共 7 个。

注意在计算时,只算本质不同的串的个数。请问,字符串0100110001010001 有多少个不同的非空子串?

解析

采用 map 记录已有的字串,最后统计 map 中有多少个不同的键值对

代码

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

public class Main {
    
    

	public static void main(String[] args) {
    
    
		Scanner scanner=new Scanner(System.in);
		int ans=0;
		Map<String, Integer> map=new HashMap<String, Integer>();
		String tempString="0100110001010001";
		for(int i=0;i<tempString.length();i++) {
    
    
			for(int j=i+1;j<=tempString.length();j++) {
    
    
				String temp=tempString.substring(i, j);
				if(map.get(temp)==null) {
    
    
					map.put(temp, 1);
					ans++;
				}
			}
		}
		System.out.println(ans);
		scanner.close();
	}

}

C 数列求值

给定数列 1, 1, 1, 3, 5, 9, 17, …,从第 4 项开始,每项都是前 3 项的和。

求第 20190324 项的最后 4 位数字。

解析

因为只用记录最后4位数字,所以一直用的存储数字都对 10000 取余

代码

import java.util.Scanner;

public class Main {
    
    
public static void main(String[] args) {
    
    
	Scanner scanner=new Scanner(System.in);
	long i=1,j=1,k=1;
	long num;
	for(int start=4;start<=20190324;start++) {
    
    
		num=i+j+k;
		i=j%10000;
		j=k%10000;
		k=num%10000;
	}
	System.out.println(k);
	scanner.close();
}
}

D 数的分解

把 2019 分解成 3 个各不相同的正整数之和,并且要求每个正整数都不包含数字 2 和 4,一共有多少种不同的分解方法?

注意交换 3 个整数的顺序被视为同一种方法,例如 1000+1001+18 和1001+1000+18 被视为同一种。

解析

挨个枚举

代码

import java.security.Principal;
import java.util.Scanner;

public class Main {
    
    
	static boolean isprim(int num) {
    
    
		while(num!=0) {
    
    
			if(num%10==2||num%10==4) {
    
    
				return false;
			}
			num/=10;
		}
		return true;
	}

	public static void main(String[] args) {
    
    
		Scanner scanner = new Scanner(System.in);
		int ans=0;
		for (int i = 1; i < 2019; i++) {
    
    
			for (int j = i; j < 2019; j++) {
    
    
				if(i==j) {
    
    
					continue;
				}
				for (int k = j; k < 2019; k++) {
    
    
					if(k==i||k==j) {
    
    
						continue;
					}
					if(isprim(i)&&isprim(j)&&isprim(k)&&i+j+k==2019)
					{
    
    
						ans++;
						System.out.println(i + " " + j + " "  + k);
					}
				}
			}
		}
		System.out.println(ans);
		scanner.close();
	}

}

E 迷宫

下图给出了一个迷宫的平面图,其中标记为 1 的为障碍,标记为 0 的为可以通行的地方。
010000
000100
001001
110000
迷宫的入口为左上角,出口为右下角,在迷宫中,只能从一个位置走到这个它的上、下、
左、右四个方向之一。 对于上面的迷宫,从入口开始,可以按DRRURRDDDR 的顺序通过迷宫,
一共 10 步。其中 D、U、L、R 分别表示向下、向上、向左、向右走。 对于下面这个更
复杂的迷宫(30 行 50 列),请找出一种通过迷宫的方式, 其使用的步数最少,在步数
最少的前提下,请找出字典序最小的一个作为答案。 请注意在字典序中D<L<R<U。

解析

BFS 算法的使用

代码

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Main {
    
    
	static Scanner scanner = new Scanner(System.in);
	static int[][] stepArr = {
    
     {
    
     1, 0 }, {
    
     0, 1 }, {
    
     0, -1 }, {
    
     -1, 0 } }; // D R L U
	static String[] direction = {
    
     "D", "R", "L", "U" }; // 与stepArr对应
	static int[][] map = new int[30][50]; // 记录地图
	static boolean[][] visit = new boolean[30][50]; // 记录是否访问
	// 构造结点类

	public static class P {
    
    
		public int x;
		public int y;
		public String roadString;

		P(int x, int y) {
    
    
			this.x = x;
			this.y = y;
		}
	}

	public static void main(String[] args) {
    
    
		for (int i = 0; i < 30; i++) {
    
    
			String string = scanner.nextLine();
			for (int j = 0; j < 50; j++) {
    
    
				map[i][j] = string.charAt(j) - '0';
			}
		}
		BFS();
	}

	static void BFS() {
    
    
		Queue<P> queue = new LinkedList<P>();// 构造队列
		P start = new P(0, 0); // 起点为左上角(0,0)
		start.roadString = "";
		visit[0][0] = true;
		queue.offer(start); // 将起点压入队列
		while (!queue.isEmpty()) {
    
     // 队列不空执行
			P now = queue.poll(); // 获取并移除此队列的头,如果此队列为空,则返回 null。
			if (now.x == 29 && now.y == 49) {
    
    // 到达终点
				System.out.println(now.roadString);
				return;
			} else {
    
    
				for (int i = 0; i < 4; i++) {
    
     // 遍历四个方向
					int newX, newY;
					newX = now.x + stepArr[i][0];
					newY = now.y + stepArr[i][1];
					if (newX >= 0 && newX < 30 && newY >= 0 && newY < 50 && !visit[newX][newY]
							&& map[newX][newY] == 0) {
    
    
						// 下一个节点没越界、没访问、是可通过的
						P next = new P(newX, newY);
						next.roadString = now.roadString + direction[i];
						visit[newX][newY] = true; // 标记此点已访问
						queue.offer(next);
					}
				}
			}
		}

	}
}

F 特别数的和

小明对数位中含有 2、0、1、9 的数字很感兴趣(不包括前导 0),

在 1 到40 中这样的数包括 1、2、9、10 至 32、39 和 40,共 28 个,他们的和是 574。

请问,在 1 到 n 中,所有这样的数的和是多少?

Input

输入一行包含一个整数 n。

Output

输出一行,包含一个整数,表示满足条件的数的和。

解析

枚举即可

代码

import java.util.Scanner;

public class Main {
    
    
	static boolean isprim(int n) {
    
    
		while (n != 0) {
    
    
			if (n % 10 == 2 || n % 10 == 0 || n % 10 == 1 || n % 10 == 9) {
    
    
				return true;
			} else {
    
    
				n /= 10;
			}
		}
		return false;
	}

	public static void main(String[] args) {
    
    
		// TODO Auto-generated method stub
		Scanner scanner = new Scanner(System.in);
		int n;
		n = scanner.nextInt();
		int ans = 0;
		for (int i = 1; i <= n; i++) {
    
    
			if (isprim(i)) {
    
    
				ans += i;
			}
		}
		System.out.println(ans);
		scanner.close();
	}

}

G 外卖店优先级

“饱了么”外卖系统中维护着 N 家外卖店,编号 1 ∼ N。

每家外卖店都有一个优先级,初始时 (0 时刻) 优先级都为 0。

每经过 1 个时间单位,如果外卖店没有订单,则优先级会减少 1,最低减到 0;

而如果外卖店有订单,则优先级不减反加,每有一单优先级加 2。

如果某家外卖店某时刻优先级大于 5,则会被系统加入优先缓存中;

如果优先级小于等于 3,则会被清除出优先缓存。

给定 T 时刻以内的 M 条订单信息,请你计算 T 时刻时有多少外卖店在优先缓存中。

Input

第一行包含 3 个整数 N、M 和 T。

以下 M 行每行包含两个整数 ts 和 id,表示 ts 时刻编号 id 的外卖店收到一个订单。

Output

输出一个整数代表答案。

解析

将每一个订单首先按照时间顺序排序,再按照店铺顺序排序。

遍历一遍排序后的订单。记录每个店铺上一次订单的时间 last 。每次遍历时,便可求的这次订单距离上次订单中间有多少个单位时间没有订单,需要减去。减去以后再统计在此时刻店铺的订单数,把得分加上此时可的订单得分。按照这种顺序直至遍历完。最后还需计算最受一次订单的下单时间与要求的 T 时刻之间的间隔,同样,间隔时间也得减去

代码

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Scanner;

public class Main {
    
    
	static Scanner scanner = new Scanner(new BufferedInputStream(System.in));// 大量数据时提高读取速率
	static final int MAX = 100010;

	static class Order {
    
     // 订单类
		public int ts;
		public int id;

		public Order(int ts, int id) {
    
    
			// TODO Auto-generated constructor stub
			this.ts = ts;
			this.id = id;
		}
	}

	static ArrayList<Order> list = new ArrayList<>();
	static int N;
	static int M;
	static int T;
	static int[] last = new int[MAX]; // 上一次有订单的时间
	static int[] score = new int[MAX]; // 每个店铺的得分
	static boolean[] st = new boolean[MAX]; // 记录是否存在于优先队列中

	public static void main(String[] args) {
    
    
		N = scanner.nextInt();
		M = scanner.nextInt();
		T = scanner.nextInt();
		int[] shop = new int[N + 1]; // 记录店铺
		for (int i = 1; i <= N; i++) {
    
    
			shop[i] = 0;
		}
		for (int i = 0; i < M; i++) {
    
    
			list.add(new Order(scanner.nextInt(), scanner.nextInt()));
		}
		Collections.sort(list, new Comparator<Order>() {
    
     // 排序实现
			public int compare(Order order1, Order order2) {
    
    
				if (order1.ts != order2.ts)
					return order1.ts > order2.ts ? 1 : -1;
				else {
    
    
					return order1.id > order2.id ? 1 : -1;
				}
			}
		});
		 // 遍历每一个订单
		for (int i = 0; i < M; i++) {
    
    
			int j = i;
			while (j < M && list.get(i).id == list.get(j).id && list.get(i).ts == list.get(j).ts) // 同一时间同一店铺
				j++; // 记录连续订单的最后一个的下标(方便计算最终该时刻与上一次订单之间的数目)
			int t = list.get(i).ts; // 当前连续订单的时刻
			int id = list.get(i).id; // 当前连续订单所属店铺

			score[id] -= t - last[id] - 1; // 减去当前时刻距离上一次时刻没有订单的单位时间得分
			if (score[id] < 0)
				score[id] = 0;
			if (score[id] <= 3)
				st[id] = false;
			last[id] = t; // 更新上一次订单的时间
			
			//上面是处理t时刻之前的减, 下面处理t时刻的加
			score[id] += (j - i) * 2; // 加上当前时刻的订单得分
			if (score[id] > 5)
				st[id] = true;
			i=j-1; // 下一次遍历从 j 开始进行(后面会执行 i++ ,所以得减 1)
		}
		
		// 考虑店铺最后一次有订单时刻却还未到 T 的情况(此时订单已经遍历完,也可以理解为 T 大于最后一个订单的 ts)
		for(int i=1;i<=N;i++) {
    
    
			if(last[i]<T) {
    
     
				score[i]-=T-last[i];
				if(score[i]<=3) {
    
    
					st[i]=false;
				}
			}
		}
		// 统计加入优先队列的个数
		int count=0;
		for(int i=1;i<=N;i++) {
    
    
			if(st[i]) {
    
    
				count++;
			}
		}
		System.out.println(count);
	}

}

H 人物相关性分析

小明正在分析一本小说中的人物相关性。

他想知道在小说中 Alice 和 Bob有多少次同时出现。

更准确的说,小明定义 Alice 和 Bob“同时出现”的意思是:在小说文本中 Alice 和 Bob 之间不超过 K 个字符。

例如以下文本:This is a story about Alice and Bob. Alice wants to send a private message to Bob.

假设 K = 20,则 Alice 和 Bob 同时出现了 2 次,分别是”Alice and Bob”和”Bob. Alice”。

前者 Alice 和 Bob 之间有 5 个字符,后者有 2 个字符。

注意:

    1. Alice 和 Bob 是大小写敏感的,alice 或 bob 等并不计算在内。
    1. Alice 和 Bob 应为单独的单词,前后可以有标点符号和空格,但是不能有字母。例如 Bobbi 并不算出现了 Bob。

Input

第一行包含一个整数 K。

第二行包含一行字符串,只包含大小写字母、标点符号和空格。长度不超过 1000000。

Output

输出一个整数,表示 Alice 和 Bob 同时出现的次数。

解析

采用两个动态数组存储分别存储每个 Alice 和 Bob 的首字母下标,最后分别统计出每个 Alice 的前面 K 个范围的区间里有多少个 Bob、每个 Bob 的前面 K 个范围的区间里有多少个 Alice ,最后将两个统计的结果相加即为最终答案

代码

import java.io.BufferedInputStream;
import java.util.Scanner;
import java.util.Vector;

public class Main {
    
    
	static Scanner scanner = new Scanner(new BufferedInputStream(System.in));
	static Vector<Integer> Alice = new Vector<>(); // 创建动态数组存储名字出现的位置
	static Vector<Integer> Bob = new Vector<>();
	static int K;
	static String string;

	// 检查字符是否为字母,因为名字的前后不能有字母
	static boolean check(char c) {
    
    
		if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
			return false; // 是字母,返回false
		else
			return true; // 是符号,返回true
	}

	public static void main(String[] args) {
    
    
		K = scanner.nextInt();
		scanner.nextLine();  // 读取多余的换行符
		string = scanner.nextLine(); // 换行符为结束标志
		// 遍历string字符串找到所有 Alice 的下标
		for (int i = 0; i + 5 <= string.length(); i++) {
    
    
			if ((i == 0 || check(string.charAt(i - 1))) && (i + 5 == string.length() || check(string.charAt(i + 5)))) {
    
    // 检查是否前后字符满足规格要求
				if (string.substring(i, i + 5).equals("Alice")) // 判断得到的字符是否为 Alice
					Alice.add(i);
			}
		}
		// 遍历string字符串找到所有 Bob 的下标
		for (int i = 0; i + 3 <= string.length(); i++) {
    
    
			if ((i == 0 || check(string.charAt(i - 1))) && (i + 3 == string.length() || check(string.charAt(i + 3)))) {
    
    // 检查是否前后字符满足规格要求
				if (string.substring(i, i + 3).equals("Bob")) // 判断得到的字符是否为 Bob
					Bob.add(i);
			}
		}
		long res = 0; // 记录答案总数
		// 计算每一个 Alice 前面有多少个 Bob 并求和
		for (int i = 0; i < Alice.size(); i++) {
    
    
			int l = 0, r = -1;
			while (r + 1 < Bob.size() && Alice.get(i) > Bob.get(r + 1))
				r++; // 找到在K的范围内的最后一个Bob
			while (l <= r && Alice.get(i) > Bob.get(l) + 3 + K)
				l++; // 找到在K的范围内的第一个Bob
			res += r - l + 1;
		}
		// 计算每一个 Bob 前面有多少个 Alice 并求和
		for (int i = 0; i < Bob.size(); i++) {
    
    
			int l = 0, r = -1;
			while (r + 1 < Alice.size() && Bob.get(i) > Alice.get(r + 1))
				r++; // 找到在K的范围内的最后一个Alice
			while (l <= r && Bob.get(i) > Alice.get(l) + 5 + K)
				l++; // 找到在K的范围内的第一个Alice
			res += r - l + 1;
		}
		System.out.println(res);
	}

}

I 后缀表达式

给定 NN 个加号、MM 个减号以及 N + M + 1N+M+1 个整数 A_1, A_2, · · · , A_{N+M+1}A1,A2,⋅⋅⋅,A**N+M+1,

小明想知道在所有由这 NN 个加号、MM 个减号以及 N + M + 1N+M+1 个整数凑出的合法的后缀表达式中,

结果最大的是哪一个?请你输出这个最大的结果。

例如使用1 2 3 + -123+−,则 “2 3 + 1 -23+1−” 这个后缀表达式结果是 44,是最大的。

Input

第一行包含两个整数 NN 和 MM

第二行包含 N + M + 1N+M+1 个整数 A_1, A_2, · · · , A_{N+M+1}A1,A2,⋅⋅⋅,A**N+M+1。

Output

输出一个整数,代表答案。

解析

情况分为三种情况考虑

负数与负号的数量形同:所有数的绝对值相加

负数多于负号数目:A 一般情况下与第一种情况相同,即为所有数的绝对值之和。B 当全为负数时 :所有数的绝对值之和减去2倍的最大负数。 C 当负号数量为0时:所有数直接做和即为最大值

负数少于负号数目:A 一般情况下与第一种情况相同,即为所有数的绝对值之和。 B 当没有负数时:所有数的绝对值之和加上2倍的最小正数

代码

import java.io.BufferedInputStream;
import java.util.Scanner;

public class Main {
    
    
	static Scanner scanner = new Scanner(new BufferedInputStream(System.in));
	static int minz = Integer.MAX_VALUE; // 记录最小正数
	static int maxz = Integer.MIN_VALUE; // 记录最大负数
	static long sumNum = 0; // 记录所有数绝对值之和
	static long sumN = 0; // 记录所有数之和
	static int countF = 0, countZ = 0; // 分别记录负数和正数的个数
	static int N, M;
	public static void main(String[] args) {
    
    
		N = scanner.nextInt();
		M = scanner.nextInt();
		for (int i = 0; i <= M + N; i++) {
    
    
			int temp = scanner.nextInt();
			sumNum += Math.abs(temp); // 绝对值求和
			sumN += temp; // 数求和
			if (temp < 0) {
    
     // 负数
				countF++;
				maxz = Math.max(maxz, temp); // 更新最大负数
			} else {
    
    
				countZ++; // 正数
				minz = Math.min(minz, temp); // 更新最小正数
			}
		}
		if (countF == M) {
    
     // 负数个数等于减号个数
			System.out.println(sumNum);
		} else if (M == 0) {
    
     // 减号个数为 0 个
			System.out.println(sumN);
		} else if (countF > M) {
    
     // 负数个数大于减号个数
			if (countZ == 0) {
    
     // 全是负数
				System.out.println(sumNum + 2 * maxz);
			} else {
    
    
				System.out.println(sumNum);
			}
		} else {
    
     // 负数个数小于减号个数
			if (countF == 0) {
    
     // 负数个数为 0 个
				System.out.println(sumNum - 2 * minz);
			} else {
    
    
				System.out.println(sumNum);
			}
		}

	}

}

G 灵能传输

暂无,如果有好的解析文章欢迎留言推荐

结语

如果你发现文章有什么问题,欢迎留言指正。
如果你觉得这篇文章还可以,别忘记点个赞加个关注再走哦。
如果你不嫌弃,还可以关注微信公众号———梦码城(持续更新中)。
梦码在这里感激不尽!!

猜你喜欢

转载自blog.csdn.net/qq_45724216/article/details/113811559