0
点赞
收藏
分享

微信扫一扫

最后的挣扎--蓝桥杯Java2021B组题解

精进的医生 2022-04-13 阅读 19

文章目录

前言

昨天随便瞄了一眼去年的Java B组的题目,一来就先搞出4题,当然不保证是最优解。

今天主要还是以阐述思路为主,适当优化别人的代码,毕竟这种题解网上都不少,我只是再把具体的思路复述一遍,力求能够摸清楚一点套路。

我们按照题目难度来说名。

首先是昨天的4题,不用想,这个妥妥送分。

ASC

在这里插入图片描述

public class ASC {
    public static void main(String[] args) {
        System.out.println((int) 'L');
    }
}

卡片

在这里插入图片描述

public class 卡片 {
    //由题意知道1的消耗是最大的,所以没有必要去把0-9的那个去统计
    static int count = 2021;
    public static void main(String[] args) {

        for (int i = 1; i <=10000; i++) {
            String temp = String.valueOf(i);
            if(temp.contains("1")){
                for (char c : temp.toCharArray()) {
                    if(c=='1'){
                        count--;
                    }
                }

            }

            if(count==0){
                System.out.println(temp);
                break;
            }else if (count<0){
                System.out.println(i-1);
                break;
            }


        }
    }
}

时间限制

在这里插入图片描述

class Time{
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        long time = scanner.nextLong();
        time /=1000;
        int a= (int) (time % (24 * 3600));
        int h = a / 3600;
        a %= 3600;
        int m = a/60;
        int s = a%60;
        System.out.printf("%02d:%02d:%02d\n",h,m,s);


    }
}

这里值得一提的是 java 其实还提供了printf()这个函数,所以我们不需要输出的那么辛苦。

杨辉三角

在这里插入图片描述

昨天太晚了,没注意,给的代码是原来没调好的。

public class 杨辉三角 {


    static int[] yanghui;//搞大一点
    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        if(n==1){
            System.out.println(n);
        }

        yanghui = new int[1000000];//搞一点,理论上可以先算一个阈值 n*n/2 <=10000000
        yanghui[0]=1;
        yanghui[1]=1;
        yanghui[2]=1;

        int idx = 2; //当前第第几个
        for (int i=3;;i++){
            //卡阈值死磕,来骗~,现在是从第三层开始
            idx++;
            yanghui[idx]=1;
            int j=1;
            for (;j<i-1;j++){
                idx++;
                yanghui[idx]=yanghui[idx-(i)]+yanghui[idx+1-i];
                //条件判断
                if(yanghui[idx]==n){
                    System.out.println(idx+1);
                    return;
                }
            }
            idx++;
            yanghui[idx]=1;

        }


    }
}

怎么说呢,肯定不是最优解,不过骗到是应该能够骗点分数。

货物摆放

在这里插入图片描述
说句实话,我对这种题目不是很敏感,意思其实很好理解,说白了就是 一个数组,你去组合成三个数字,然后相乘等于自己本身。

我当时的第一想法肯定是暴力,暴力枚举 但是 n的三次幂挺大的。所以我就在想这些数有没有什么规律啥的。然后,什么数字相乘能够得到自己本身,那么不就是可以被自己整除的数子嘛,也就是约数呀。所以代码出来了。

求取约数

首先我们要做的是求约数,这里的话是有一个公式的。
首先是最简单的

for(int i=1;i<=Math.sqrt(n);i++){
	if(n%i==0){
		res.add(i);
		res.add(n/i);}
	}
}

这个的时间复杂度是O log n
本来是这样的,但是由于你的 i 都是小于人家方根的,所以后面那个if一定成立,减少了很多不必要的运算。

for(int i=1;i<Math.sqrt(n);i++){
	if(n%i==0){
		res.add(i);
		}
	if(i*i!=n){
		res.add(n/i);
	}
}

public class 货物摆放 {

        static int ans = 0;
        static long num = 2021041820210418L;

        public static void main(String[] args) {
            long end = (long)Math.sqrt(num);
            Set<Long> div = new HashSet<>();

            for (long i = 1; i <= end; i++) {
                if (num % i == 0) {
                    div.add(num/i);
                    div.add(i);
                }
            }

            Long[] arr = div.toArray(new Long[0]);
            for (long i : arr) {
                for (long j : arr) {
                    for (long k : arr) {
                        if (i * j * k == num) {
                            ans++;
                        }
                    }
                }
            }

            System.out.println(ans);
        }

    }

直线

在这里插入图片描述

这两个填空题的话,怎么说呢,难度上其实都应该差不多,不过这个直线的创新性稍微强一点。
这里的想法也很简单,没错就是生成那个矩阵,然后去枚举,重点是去重,这里去重的话,直接考虑使用Set。反正都是暴力。

我们这边就先考虑 有斜线的情况,不考虑连接成与坐标轴平行的线。

后面再加回去嘛,主要是公式这边不好处理。

public class 直线 {

    public static void main(String[] args) {
        Set<Map<Double,Double>> linear = new HashSet<>();
        List<Map<Integer,Integer>> points = new ArrayList<>();
        //初始化所有点
        for (int i=0;i<20;i++){
            for(int j=0;j<21;j++){
                HashMap<Integer, Integer> temp = new HashMap<>();
                temp.put(i,j);
                points.add(temp);
            }
        }

        //遍历计算点
        for (int i=0;i<points.size();i++){
            for(int j=i+1;j<points.size();j++){
                double x1=0;double y1=0;
                double x2=0;double y2=0;
                //解包
                for (Map.Entry<Integer, Integer> point1 : points.get(i).entrySet()) {
                    x1=point1.getKey();
                    y1=point1.getValue();
                }
                for (Map.Entry<Integer, Integer> point1 : points.get(j).entrySet()) {
                    x2=point1.getKey();
                    y2=point1.getValue();
                }

                if(x1==x2||y1==y2){
                    continue;
                    //水平的情况,先不要
                }
                //计算斜率
                double k=(y2-y1)/(x2-x1);
                double b=(x2*y1 -x1*y2)/(x2-x1);

                HashMap<Double, Double> temp = new HashMap<>();
                temp.put(k,b);
                //对于这种数据类型,equal方法是按照值去对比的
                linear.add(temp);

            }


        }
        System.out.println(linear.size()+20+21);
    }
}

路径

在这里插入图片描述

这个题目本身不是很难,主要是构建那个图稍微麻烦一点。
构建好之后,咱们再去找最短路径。

这里有两个算法一个是 弗洛伊德,还有一个是 迪杰特斯 的方法。
最简单的当然是第一个。

public class Main {
	static int[][] graph = new int[2050][2050];
	static final int INF = 0x3f3f3f3f;
	
	private static void floyd() {
		for (int k = 1; k <= 2021; k++) {
			for (int i = 1; i <= 2021; i++) {
				for (int j = 1; j <= 2021; j++) {
					if (i != j && graph[i][j] > graph[i][k] + graph[k][j]) {
						graph[i][j] = graph[i][k] + graph[k][j];
					}
				}
			}
		}
	}
	
	private static int gcd(int a, int b) {
		return b == 0 ? a : gcd(b, a % b);
	}
	
	public static void main(String[] args) {
		for (int i = 1; i <= 2021; i++) {
			for (int j = 1; j <= 2021; j++) {
				graph[i][j] = INF;
			}
		}
		
		for (int i = 1; i <= 2021; i++) {
			int st = Math.max(i - 21, 1);
			for (int j = st; j <= i; j++) {
				int div = gcd(j, i);
				int lcm = i * j / div;
				graph[i][j] = lcm;
				graph[j][i] = lcm;
			}
		}
		
		floyd();
		
		System.out.println(graph[1][2021]); // 10266837
	}
	
}

这里简单说一下原理。其实很简单
在这里插入图片描述

看那个大循环就知道了,A–》B假设走A中转看距离,然后走完后,在假设走B中转,知道假设玩全部。
例如A–》D 第2次遍历假设到走B近,那么此时更新到B中转,然后再问遍历的C中转,发现在原来的基础上还更近,那么此时再加上走C的距离,此时你就得到了A–》D 中转 B C 近。

接的下来是后面三道大题冲刺。 按照刷题的经验,基本上第十题应该是最难的,第一题应该是简单的,其他的不好说,所以一定要先全部预览一下题目。包括,昨天,我就是9,10题基本上没看,以为很难。结果第九题嘿嘿,还是能骗分的。

到这里,已经“大力飞砖”了大概 7 题,其实发现,这些题目,比原来的数据量大,填空题几乎不可能手推出来,而且考到了比较多的数据结构方面的东西,对比原来的 13 14 包括20 和原来的模拟题怎么说呢,题目是越来越绕了。我这糟糕的语文能力。

双向队列

在这里插入图片描述
这里还要我说嘛,工具类,暴力来骗~

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

public class Main {

	public static void main(String[] args) {
		Scanner in = new Scanner(new BufferedInputStream(System.in));
		int n = in.nextInt(), m = in.nextInt();
		Integer[] arr = new Integer[n + 1];
		
		for (int i = 1; i <= n; i++) {
			arr[i] = i;
		}
		
		for (int i = 0; i < m; i++) {
			int p = in.nextInt();
			int split = in.nextInt();
			if (p == 0) {
				Arrays.sort(arr, 1, split + 1, (a, b) -> Integer.compare(b, a));
			} else {
				Arrays.sort(arr, split, n + 1);
			}
		}
		
		for (int i = 1; i <= n; i++) {
			if (i > 1) {
				System.out.print(" ");
			}
			System.out.print(arr[i]);
		}
		
		in.close();
	}
    
}

这里有一个输入优化,请务必记住

new Scanner(new BufferedInputStream(System.in))

到此,好骗的大题目估计就骗到了~

括号匹配

为什么先说在这个咧,原因很简单,dp,我想不出来,我只能想到暴力!

public class 括号匹配 {
    static int count = 0;
    static int end = 0;
    public static void main(String[] args) {

        Scanner scanner = new Scanner(new BufferedInputStream(System.in));
        String next = scanner.next();
        for (char c : next.toCharArray()) {
            if(c=='(') end++;
        }
       
        f(0,0);
        System.out.println(count%100000007);
    }

    public static void f(int left,int right){
        //我们是从0开始放,放到end下标的时候,说明我们前面的都放完了
        if(left==end){
            count++;
            count%=100000007;
            return;
        }
        f(left+1,right);
        if(left>right){
            f(left,right+1);
        }
    }
}

不过这个骗不了几个分。

最少砝码

在这里插入图片描述

这道题目是第七题你敢信,反正第一眼我没啥思路,模拟暴力,也不对。
然后我看了题解,陷入了沉默,规律很好找,只是我找到方向错了。

这个题目怎么说呢,还是假设嘛
还是一个一个推,从一开始
选1、2的砝码可以满足1=1,2=2,1+2=3
选1、3的砝码可以满足1=1,2=3-1,3=3,4=3+1

也就是这样想
假设质量1 要称出来 只能有1
假设质量2 要出来 只能有 1 2
假设质量3 要出来 1 2 就够了
假设质量4 要出来 1 3 就够了

此时 1 3 可以表示 1 2 3 4
对于7: 1 4 6 我可以表示从1到7,对于质量6我也能够表示
一直推下去
选1、3、9的组合可以满足小于等于13(13=1+3+9)的所有重量

然后打表

序号砝码质量最大表示质量
111
234
3913
42740

此时规律不就出来了,我只要看你的那个值的范围,然后生成这个表格,不仅我可以知道你的那个长度
我还能知道你是什么砝码组成。

import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		sc.close();
		int weight = 1;
		int count = 1;
		int total = 1;
		while (total < n) {
			count++;
			weight *= 3;
			total += weight;
		}
		System.out.println(count);
	}
}

快捷键

之后是关于ecplise的快捷键,这里你只需要记住三个。

和一个设置。

说句实话,搞不懂,那么费劲的玩意怎么还活着,IDEA比他牛,收费,这个没办法,但是我VSCODE 不是吊打它嘛!要不是比赛,真不想用那破玩意。界面难看用起来还膈应,你说装插件,我靠我直接用vscode不比他香,java 8 不支持了,用老版本能咋地,说的你ecplise 新版本就支持java 8一样。

第一个是关于代码提示设置。这个很简单。

在这里插入图片描述
在这里插入图片描述
点击一下第二个
在这里插入图片描述

快捷键

一个是 crtl + 1 代码修复

一个是 Ctrl+Shift+O 自动引导类包,不过,第一个可以有这个功能

还有一个是 alt + shift + s 作用和 idea 的 alt + ins 一样
其他的没必要记,至于代码调试,自己打断点,快捷键和idea差不多,不行就用 那个图形化的提示点点嘛,实在不行自己输出结果自己看。

总结

关于一些,什么常见的数学公式啥的,我记得也少。

这里再水边补充一下。

求约数

for(int i=1;i<=Math.sqrt(n);i++){
	if(n%i==0){
		res.add(i);
		res.add(n/i);}
	}
}

快速幂乘

int res = 1;
int a 你要求的数,n是幂数
while(n>0){
	if(n%2!=0){
		res*=a;
		n=n-1;
	}
	n/=2;
	a*=a;
}

快速幂取余

int res = 1;
int a 你要求的数,n是幂数
int m 是余数
while(n>0){
	if(n%2!=0){
		res*=a%m;
		n=n-1;
	}
	n/=2;
	a*=a%m;
}
a = a%m;

这个是公式退出来的。
由于是java 的话 int 会得到整数 5/2 和 4/2效果一样,所以可以省略 n-1 但是如果你是Python 的话不行。

欧拉取公约数

public static int gcd(int m,int n){
	return n==0?m:gcd(n,m%n);
}

最小公倍数

这个就是 m*n / gcd(m,n)

分解质因数

public static String res(int num){
	StringBuffer sb = new StringBuffer(num + "=");
	int i=2;
	while(i<=num){
		if(num%i==0{
			sb.append(i).append("*");
			num=num/i;
			i=2
		}else{
			i++;
		}
	}
	return sb.toString().substring(0, sb.toString().length() - 1);
}

最后祝我好运吧!谢谢

举报

相关推荐

0 条评论