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

Posted Huterox

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最后的挣扎--蓝桥杯Java2021B组题解相关的知识,希望对你有一定的参考价值。

文章目录

前言

昨天随便瞄了一眼去年的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 

以上是关于最后的挣扎--蓝桥杯Java2021B组题解的主要内容,如果未能解决你的问题,请参考以下文章

计算思维题少儿编程 蓝桥杯青少组计算思维题真题及解析第2套

第十二届蓝桥杯C++组省赛B组题解(A -- B)

第十二届蓝桥杯B组试题答案

第十三届蓝桥杯模拟赛第二期JAVA组个人题解

Java第六届蓝桥杯JAVA组C组省赛题解

Java第六届蓝桥杯JAVA组B组省赛题解