大家好,我是snippet,今天是刷蓝桥真题的第十一天,今天的知识包含gcd,动态规划,这段时间我们也学了很多新知识,要及时巩固,下面是我今天的题解
目录
一、卡片
二、路径
三、字符统计
四、费用报销
题目链接:卡片 - 蓝桥云课 (lanqiao.cn)
题目内容:
题目描述
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
小蓝有很多数字卡片,每张卡片上都是数字 0 到 9。
小蓝准备用这些卡片来拼一些数,他想从 1 开始拼出正整数,每拼一个,就保存起来,卡片就不能用来拼其它数了。
小蓝想知道自己能从 11 拼到多少。
例如,当小蓝有 30 张卡片,其中 0 到 9 各 3 张,则小蓝可以拼出 1 到 10,
但是拼 11 时卡片 1 已经只有一张了,不够拼出 11。
现在小蓝手里有 0 到 99 的卡片各 2021 张,共 20210 张,请问小蓝可以从 11 拼到多少?
提示:建议使用计算机编程解决问题。
运行限制
- 最大运行时间:1s
- 最大运行内存: 128M
解题思路:
先用一个数组存1-9每个数字含有的个数(2021),从数字1开始遍历,当1-9哪个数字用完的时候,我们就输出遍历到的那个数的前一个数,因为拼这个数的字符已经不够了
代码:
package 蓝桥杯31天真题冲刺.Day11;
import java.util.Arrays;
/**
* @author snippet
* @data 2023-03-14
* 卡片-蓝桥云课
*/
public class T1_卡片 {
static int[] a = new int[10];
static int check(int n) {
int k = n;
while (k > 0) {
int t = k % 10;
if (a[t] <= 0) return n-1;
a[t]--;
k /= 10;
}
return -1;
}
public static void main(String[] args) {
Arrays.fill(a, 2021);
for (int i = 1; ;i++) {
if (check(i) != -1) {
System.out.println(check(i));
return;
}
}
}
}
题目链接:路径 - 蓝桥云课 (lanqiao.cn)
题目内容:
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
小蓝学习了最短路径之后特别高兴,他定义了一个特别的图,希望找到图 中的最短路径。
小蓝的图由 2021 个结点组成,依次编号 1 至 2021。
对于两个不同的结点 a, b,如果 a 和 b 的差的绝对值大于 21,则两个结点 之间没有边相连;如果 a 和 b 的差的绝对值小于等于 21,则两个点之间有一条 长度为 a 和 b 的最小公倍数的无向边相连。
例如:结点 1 和结点 23 之间没有边相连;结点 3 和结点 24 之间有一条无 向边,长度为 24;结点 15 和结点 25 之间有一条无向边,长度为 75。
请计算,结点 1 和结点 2021 之间的最短路径长度是多少。
提示:建议使用计算机编程解决问题。
运行限制
- 最大运行时间:1s
- 最大运行内存: 128M
解题思路:
这个题考察的是gcd和动态规划,从1开始遍历,每次的遍历判断区间为21,当num数组未赋初始值的时候记得赋给初始值,状态转移式为:num[j] = Math.min(num[j], (i*j)/gcd(i,j) + num[i]);
代码:
package 蓝桥杯31天真题冲刺.Day11;
/**
* @author snippet
* @data 2023-03-14
* 路径-蓝桥云课
*/
// 01背包+gcd
public class T2_路径 {
static int[] num = new int[2022];
public static void main(String[] args) {
for (int i = 1; i <= 2021; i++) {
for (int j = i+1; j <= i+21; j++) {
if (j == 2022) break;
if (num[j] == 0) {
// 初始化
num[j] = num[i] + (i*j)/gcd(i,j);
} else {
num[j] = Math.min(num[j], (i*j)/gcd(i,j) + num[i]);
}
}
}
System.out.println(num[2021]);
}
// 求最大公约数
static int gcd(int a, int b) {
return b != 0 ? gcd(b, a%b): a;
}
}
题目链接:字符统计 - 蓝桥云课 (lanqiao.cn)
题目内容:
问题描述
给定一个只包含大写字母的字符串 S, 请你输出其中出现次数最多的字符。
如果有多个字母均出现了最多次, 按字母表顺序依次输出所有这些字母。
输入格式
一个只包含大写字母的字符串 S.
输出格式
若干个大写字母,代表答案。
样例输入
BABBACAC
样例输出
AB
评测用例规模与约定
对于 100% 的评测用例, 1≤∣S∣≤10^6.
运行限制
- 最大运行时间:1s
- 最大运行内存: 512M
解题思路:
记录字符的使用次数,并且输出使用次数最大的所有字符,我们用一个一维数组来记录每个字符的使用次数,用一个max来记录字符的最大使用次数即可
代码:
package 蓝桥杯31天真题冲刺.Day11;
import java.io.*;
/**
* @author snippet
* @data 2023-03-14
* 字符统计-蓝桥云课
*/
public class T3_字符统计 {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
static int[] c = new int[26];
static int maxs = 0;
public static void main(String[] args) throws IOException {
String s = br.readLine().split(" ")[0];
for (int i = 0; i < s.length(); i++) {
int t = ++c[s.charAt(i)-'A'];
maxs = Math.max(maxs, t);
}
for (int i = 0; i < c.length; i++) {
if (c[i] == maxs) {
pw.print((char) (i+'A'));
}
}
pw.flush();
br.close();
}
}
题目链接:费用报销 - 蓝桥云课 (lanqiao.cn)
题目内容:
问题描述
小明在出差结束后返回了公司所在的城市, 在填写差旅报销申请时, 粗心 的小明发现自己弄丢了出差过程中的票据。
为了弥补小明的损失, 公司同意小明用别的票据进行报销, 但是公司财务 要求小明提交的票据中任意两张的日期差不小于 K 天, 且总金额不得超过实际 差旅费用 M 。
比如财务要求 K=7 时, 若小明提交了一张 1 月 8 日的票据, 小明就不能 提交 1 月 2 日至 1 月 14 日之间的其他票据, 1 月 1 日及之前和 1 月 15 日及之 后的票据则可以提交。
公司的同事们一起给小明凑了 N 张票据, 小明现在想要请你帮他整理一 下, 从中选取出符合财务要求的票据, 并使总金额尽可能接近 M 。
需要注意, 由于这些票据都是同一年的, 因此 12 月底的票据不会影响到 1 月初票据的提交。这一年不是闰年。
输入格式
第 1 行: 3 个整数,N,M,K
第 2…N+1 行: 每行 3 个整数mi,di,vi, 第 i+1 行表示第 i 张票据时间 的月份 mi 和日期 di,vi 表示该票据的面值
输出格式
第 1 行: 1 个整数, 表示小明能够凑出的最大报销金额
样例输入
4 16 3
1 1 1
1 3 2
1 4 4
1 6 8
样例输出
10
样例说明
选择 1 月 3 日和 1 月 6 日的票据
评测用例规模与约定
对于 100%100% 的评测用例, 1≤N≤1000,1≤M≤5000,1≤K≤50,1≤mi≤ 12,1≤di≤31,1≤vi≤400
日期保证合法。
运行限制
- 最大运行时间:1s
- 最大运行内存: 512M
解题思路:
这个题的话,我也还有一点迷茫,看了怂佬的Java题解后,有点顿悟的感觉,也就跟之前写的动态规划的题目差不多,先根据一个条件进行排序(这个题根据日期的天数进行排序),再寻找需要状态转移的区间(对每个物品进行一次放入 同时判断可以放入的票据的区间),最后找到状态转移式以及进行状态转移的条件
代码:
package 蓝桥杯31天真题冲刺.Day11;
import java.io.*;
import java.util.Arrays;
import java.util.Comparator;
/**
* @author snippet
* @data 2023-03-14
* 费用报销-蓝桥云课
*/
// 动态规划-01背包
public class T4_费用报销 {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
static int N,M,K;// N表示票据的张数 M表示最大的差旅费用 K表示任意两张票据的最小日期差
static int[] m = {0,31,28,31,30,31,30,31,31,30,31,30,31};// 一维数组m存每个月的天数
static int[][] arr = new int[1010][2];// 二维数组arr每行的第一列存该票据的时长 第二列表示该票据的面值
static boolean[][] dp = new boolean[1010][5050];// 二维数组dp表示前i张票可以组成的最大m值
public static void main(String[] args) throws IOException {
String[] s = br.readLine().split(" ");
N = Integer.parseInt(s[0]);
M = Integer.parseInt(s[1]);
K = Integer.parseInt(s[2]);
for (int i = 1; i <= 12; i++) {
m[i] += m[i-1];
}
for (int i = 1; i <= N; i++) {
s = br.readLine().split(" ");
arr[i][0] = m[Integer.parseInt(s[0])-1]+Integer.parseInt(s[1]);
arr[i][1] = Integer.parseInt(s[2]);
}
// 按照时间排序
Arrays.sort(arr, 1, N+1, Comparator.comparingInt(a -> a[0]));
// 初始化
dp[0][0] = true;
int left = 0;
int max = 0;
for (int i = 1; i <= N; i++) {
//当前票据和前面已经可以放入的票据有多少不起冲突
while (arr[i][0] - arr[left+1][0] >= K) left++;
for (int j = 0; j <= M; j++) {
//前面已经可以存在的价值,放入新的以后同样可以存在
dp[i][j] = dp[i-1][j];
if (j >= arr[i][1] && dp[left][j - arr[i][1]] == true) {
dp[i][j] = true;
max = Math.max(max, j);
}
}
}
pw.println(max);
pw.flush();
br.close();
}
}