前言
蓝桥杯第十三届省赛在4月9号开始,按照以往惯例,基本填空题4道,编程题2-3道,省一基本就稳了。
蓝桥杯省赛考的比较基础,除了最后一题,其他基本都是简单或者中等题,我们不需要所有题都做出来,只需要保证自己会做的不错,那么省一基本没有什么问题。下面是我上一次参加省赛的奖状
考试技巧
根据我自己参加比赛的经历,省赛整体难度较低,大部分题目都可以暴力得部分分数,对于省赛,我们需要重点复习以下知识点
对于java组,我们必须要能够熟练掌握BigInteger,BigDecimal这2个类必须掌握,如果不会,马上去学习,这2个类可以实现大数的运算,具有奇效!!!
在省赛中,基本每次都有关于时间的题目,所以,对于时间的api,我们也必须要能够掌握,在java中,例如Data类,Calendar,LocalDate,LocalDateTime这几个类也必须掌握。
在省赛中数据结构肯定会考,基本的DFS,BFS必须要会,树的遍历,特点也要熟悉,对于图的几种基本算法也要学一下,如最短路径
上面的3点是必须掌握的,下面就是提升类的,蓝桥杯在以前一直被称为暴力杯,这是因为在前几届的蓝桥杯确实都是暴力解题,但是现在开始提升难度了,在上一届dp(动态规划)的题就开始增多了,如果想拿个好成绩,别犹豫,马上去刷动态规划的题目吧!!
接下来就是字符串相关的,这个也考的十分的多,建议去leetcode看一下字符串专栏,大致了解下常见的算法,在比赛时遇到最起码有个方向
下一点,全排列,不知道大家会不会,由于java没有现成的函数,所以建议现在自己写下函数,这个用到的几率很大
这点很重要,认真读题,认真读题,认真读题,题目建议多读几遍,彻底弄清楚意思后再开始想解题思路
对于难题,10分钟没有思路,马上跳过,先把自己能做的全部做了再思考,蓝桥杯的难度一般都是随题目号数递增的,也就是越到后面越难
做题,如果不是特别有经验,建议第一种解法都从暴力开始,然后进行优化
最后一点,蓝桥杯的测试案列特别少,你写完代码后可能觉得自己做对了,测试用例也对,然后就直接提交了,比赛结束后才发现自己没有考虑周全,这时已经为时已晚,我们在写完代码后,建议至少编写5个测试用例及以上,对代码进行测试,并且测试用例要数值比较大或者比较刁钻。
总之,蓝桥杯省赛难度不大,只要学过基本的数据结构和算法,省一基本没问题,省赛的差距就是细心,最后再重复三次,**细心,细心,细心**
真题解析
**下面对上一届的题目进行讲解说明,也就是第十二届java B组**
第一题 (ASC)
**这道题送分题,不解释,直接给出答案,76**
第二题 (卡片)
**这道题就是暴力模拟,我们定义10大小的数组代表0-9,每个值都是2021,然后循环判断,如果数组值都不为0,那么就继续。我们对循环的数字依次得到每个位数,然后再数组中进行相减就行,可能描述有点模糊,下面直接看代码。**
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] nums = new int[10];
Arrays.fill(nums, 2021);
int ans = 1;
//设置标记,是否退出循环
boolean flag = false;
while (true) {
//对于每一个num,通过字符串方式获取每一个数字
for (char num : (ans + "").toCharArray()) {
//将对于位置的数字-1,看是否为0
if (--nums[num - '0'] == 0) {
flag = true;
break;
}
}
if (flag) break;
ans++;
}
System.out.println(ans);
}
}
** 答案为:3181**
第三题 (直线)
** 这道题也简单,需要注意的就是浮点数的问题。y=kx+b,思路就是算出所有的直线的斜率k和b,然后放入set去重就行,这里需要重点注意精度问题,注意浮点数误差,我是直接使用java的BigDecimal解决的**
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashSet;
public class Main {
public static void main(String[] args) {
HashSet<String> hashSet = new HashSet<>();
for (int i = 0; i < 20; i++) {
for (int j = 0; j < 21; j++) {
for (int m = i + 1; m < 20; m++) {
for (int n = 0; n < 21; n++) {
// y = kx + b通过2个点算出 b和k,然后返回b_k字符串,存入set
String bk = getBK(i, j, m, n);
hashSet.add(bk);
}
}
}
}
//这里加20是因为有20条直线没有斜率
System.out.println(hashSet.size() + 20);
}
public static String getBK(double x1, double y1, double x2, double y2) {
// k保留小数点后50位
BigDecimal k = new BigDecimal(y1 - y2).divide(new BigDecimal(x1 - x2), 50, RoundingMode.FLOOR);
BigDecimal b = new BigDecimal(y1).subtract(new BigDecimal(x1).multiply(k));
// b和k都保留15位小数
b = b.setScale(15, RoundingMode.FLOOR);
k = k.setScale(15, RoundingMode.FLOOR);
return b + "_" + k;
}
}
** 答案为:40257**
第四题 (货物摆放)
** 这道题直接暴力解决即可,没什么难度,算出n的所有因数,然后循环判断就行**
import java.util.HashSet;
public class Main {
public static void main(String[] args) {
long num = 2021041820210418L;
HashSet<Long> hashSet = new HashSet<>();
//将num所有因数加入集合
for (long i = 1; i <= Math.sqrt(num); i++) {
if (num % i == 0){
hashSet.add(i);
hashSet.add(num / i);
}
}
long ans = 0;
//暴力对所有因数进行循环
for (Long x : hashSet) {
for (Long y : hashSet) {
for (Long z : hashSet) {
if (x * y * z == num)ans++;
}
}
}
System.out.println(ans);
}
}
** 答案:2430**
第五题 (路径)
** 这道题就是想考察图里面的最短路径问题,但是我们可以转化为dp来做,首先求出所有点到后面21个的距离,存入数组,然后进行dp即可,dp[i] = min(dp[i],dp[i-k][k]) k范围就是1-21 **
public class Main {
public static void main(String[] args) {
long[] dp = new long[2022];
//存放当前点到后面21个点的距离,下标1开始
long[][] dis = new long[2022][22];
for (int i = 1; i < 2022; i++) {
for (int j = 1; j < 22; j++) {
if (i + j > 2021) break;
dis[i][j] = getDis(i, i + j);
}
}
for (int i = 1; i < 2022; i++) {
long min = Long.MAX_VALUE;
//求出到当前点的最小值
for (int j = 1; j <= 21; j++) {
if (i - j <= 0) break;
min = Math.min(min, dp[i - j] + dis[i - j][j]);
}
if (min != Long.MAX_VALUE) dp[i] = min;
}
System.out.println(dp[dp.length - 1]);
}
public static long getDis(long a, long b) {
return a * b / gcd(a, b);
}
public static long gcd(long a, long b) {
return a % b == 0 ? b : gcd(b, a % b);
}
}
** 答案:10266837**
第六题 (时间显示)
**送分题,不解释,直接给出代码,注意输出格式,建议使用printf**
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
long time = new Scanner(System.in).nextLong();
long h = (time / 1000 / 60 / 60) % 24;
long m = (time / 1000 / 60) % 60;
long s = (time / 1000) % 60;
System.out.printf("%02d:%02d:%02d", h, m, s);
}
}
第七题 (最少砝码)
** 这道题怎么说呢,可以动态规划,可以暴力模拟,但是最优解法是平衡3进制模拟,不知道大家听说过3进制没有,这里使用3进制来做,砝码3种状态刚好对应,放左边,放右边,不放,原理就是3进制,两两组合,-1,0,1,组合后可以表示不重复的9个数**
三进制十进制-1-10011-1 -1-4-1 0-3-1 1-21 -121 031 14
** 三进制数可以表示所有 的数,又因为题目需要满足条件为,通过计算,可以求出n≥log3(2N+1),所以我们需要的砝码重量就是,x>=0,下面就可以很容易的写代码了,我说的可能不是很清楚,可以看下下面的解释,如果不理解,直接跳过也没关系,暴力,dp都能得大部分分。**
举个例子,平衡3进制的1和3,也就是 1 和 10这2个数就可以表示到11,也就是可以表示到4
十进制1,3,9,平衡三进制表示为 1 10 100,
这3个数通过加减运算就可以表示到-1-1-1到111的所有范围,也就是 (-14,14)
十进制1,3,9,27,平衡三进制表示为 1 10 100 1000,
这4个数就可以表示 -1-1-1-1到1111的所有范围也就是(-40,40)
** 如果还不明白,可以参考 对称三进制数详解 **
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
long n = new Scanner(System.in).nextLong();
int count = 1;
int i;
for (i = 1; count < n; i++) {
count += Math.pow(3, i);
}
System.out.println(i);
}
}
第八题 (杨辉三角形)
** 这道题涉及到数学推导,下面给出2种解放,第一种暴力,可以得一半的分**
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
int n = new Scanner(System.in).nextInt();
if (n == 1) {
System.out.println(1);
return;
}
//动态dp,2行进行切换
int[][] dp = new int[2][100000];
long count = 1;
dp[0][1] = 1;
int i = 1, j = 1;
//当前层数
for (int layer = 2; ; layer++) {
//每层的数量和当前层数相同
for (int k = 0; k < layer; k++) {
//简单dp
if (layer % 2 == 0) dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1];
else dp[i][j] = dp[i + 1][j] + dp[i + 1][j - 1];
count++;
if (dp[i][j++] == n) {
System.out.println(count);
return;
}
}
//根据层数判断是从0开始还是1开始
i = layer % 2 != 0 ? 1 : 0;
j = 1;
}
}
}
如果想要得全部分,那么就要进行数学推导,从数学的方面来考虑,由于过程比较复杂,篇幅有限,直接给出推导的链接,很详细,可以自己进行查看 数学推导 得分为100
第九题 (双向排序)
** 这道题也是用到数学,但是我们暴力解决可以获得60分,也还行,下面给出暴力解法的代码和数学推导的链接**
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
Integer[] arr = new Integer[n+1];
for (int i = 1; i < arr.length; i++) {
arr[i] = i;
}
for (int i = 0; i < m; i++) {
int num1 = scanner.nextInt();
int num2 = scanner.nextInt();
//直接调用api
if (num1 == 0){
Arrays.sort(arr, 1, num2+1, (o1, o2) -> o2-o1);
}else {
Arrays.sort(arr, num2, n+1);
}
}
for (int i = 1; i <= n; i++) {
System.out.print(arr[i]+" ");
}
}
}
** 由于博客已经很长了,数学推导不做结束,给出链接自行查看即可 数学推导,这个就可以得到100分**
第十题 (括号序列)
** 最后一题很难,一般都是留给打 ACM 的做的,如果不是打acm的直接跳过,对成绩没有任何影响,这道题就不进行解释了,如果感兴趣,参考 括号序列详解,这位大佬给出了详细的解法,可以参考一下**
总结
** 蓝桥杯难度主要集中在后面几题,最后一题直接放弃,我们如果没有思路,那么就使用暴力即可,能得多少分算多少,大家要相信,你觉得难,其他人也觉得难,蓝桥杯省赛,填空题4道,编程题3道,省一肯定没问题。**
** 最后再说一点,省赛不难,最重要的就是认真读题,认真读题,认真读题,细心,细心,再细心。祝愿大家都能在蓝桥杯中取得好成绩!!!**
版权归原作者 秃头披风侠. 所有, 如有侵权,请联系我们删除。