第十一届蓝桥杯大赛软件类省赛Java研究生组-题解

Posted nuist__NJUPT

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第十一届蓝桥杯大赛软件类省赛Java研究生组-题解相关的知识,希望对你有一定的参考价值。

目录

试题A :约数个数

试题B:跑步锻炼

试题C:平面分割

试题D:蛇形填数

试题E:排序

试题F:成绩统计

试题G:回文日期

试题H:作物杂交

试题I:子串分值

试题J:装饰珠


试题A :约数个数

答案:96

思路:简单枚举,注意1和本身也算约数。

public class Main 
    public static void main(String[] args) 
        int ans = 0 ;
        for(int i=1; i<=78120; i++)
            if(78120%i==0)
                ans ++ ;
            
        
        System.out.println(ans);
    

试题B:跑步锻炼

答案:8879

思路:Java日期时间API的应用,根据平年和闰年,算出总天数days,算出周一的天数a,算出初一的天数b,再算出既是初一又是周一的天数ans,那么最终的跑步路程为(days-(a+b-ans)) + (a+b-ans)*2。


import java.util.Calendar;

import static java.time.Year.isLeap;

public class Main 
    public static void main(String[] args) 
        Calendar c = Calendar.getInstance() ;
        int years = 2000;
        int same = 0 ;
        //Calendar的月份是从0到11的,不是1到12,需要注意,谨慎一点,时间API也是常考的
        c.set(years,0, 1) ;

        while(c.get(Calendar.YEAR) != 2020 || c.get(Calendar.MONTH) != 9 || c.get(Calendar.DATE) != 1)
            //从2000年1月1日开始判断,每次判断一个月的第一天,如果是周一,就用same记录
            int weekday = c.get(Calendar.DAY_OF_WEEK) - 1 ;
            if(weekday==1)
                same ++ ;
            

            if(c.get(Calendar.MONTH)<11)
                c.set(Calendar.MONTH, c.get(Calendar.MONTH)+1) ;
            else
                years ++ ;
                c.set(Calendar.YEAR, years);
                c.set(Calendar.MONTH, 0);
            
        


        long days = 0 ;
        for(int year=2000; year<=2020; year++)
            if(isLeap(year))
                days += 366 ;
            else
                days += 365 ;
            
        

        days = days - 31 - 30 - 30 ;
        long a = (days-6) / 7 + 1; //星期1
        long b = 12*20 + 10  ; //初一

        long ans = days - (a+b-same) ;

        System.out.println(2*(a+b-same)+ans);

    

试题C:平面分割

答案:1391

思路:没有思路,哈哈,我看别人的思路是让尽可能的相交,这样产生的区域就越多,至于具体怎么推导的,可以看下这个。参考链接:蓝桥杯试题E: 平面分割 - riz9 - 博客园

试题D:蛇形填数

答案:761

思路:模拟斜对角向上和向下填数过程即可。

//试题D-蛇形填数
public class Main 
    public static void main(String[] args) 
        int row = 0, col = 0 ;
        int num = 0 ;
        while(true)
            num ++ ;

            if(row==19 && col ==19)
                break ;
            

            if((row+col)%2==0) //向上走
                if(row==0)
                    col ++ ;
                else
                    row -- ;
                    col ++ ;
                
            else //向下走
                if(col==0)
                    row ++ ;
                else
                    row ++ ;
                    col -- ;
                
            

        
        System.out.println(num);
    

试题E:排序

答案:jonmlkihgfedcba

相邻交换100次,最短需要15个字符,正常前15个字符逆序,交换1+2+3+...+14=105次,故把j放到首位,交换100次,最短并且字典序最小。

public class Main 
    public static void main(String[] args) 
        int ans = 0 ;
        //前15个小写字母逆序,执行105交换,此时是最短的,要保证字典序最小,把第5个移动到首位
        System.out.println("jonmlkihgfedcba");
    

试题F:成绩统计

思路:枚举,计算即可,注意四舍五入。

import java.util.Scanner;

public class Main 
    public static void main(String[] args) 
        Scanner input = new Scanner(System.in) ;
        int n =input.nextInt() ;
        int pass = 0, excellent = 0 ;
        for(int i=0; i<n; i++)
            int grade = input.nextInt() ;
            if(grade>=85)
                excellent ++ ;
            
            if(grade>=60)
                pass++ ;
            
        
        int ans1, ans2 ;
        double x = 1.0 * pass / n * 1000;
        double y = 1.0 * excellent / n * 1000 ;
        if(x==1000)
            System.out.println(100 + "%");
        else 
            String s1 = String.valueOf(x);
            int c1 = s1.charAt(2) - '0';
            if (c1 >= 5) 
                ans1 = Integer.parseInt(s1.substring(0, 2)) + 1;
             else 
                ans1 = Integer.parseInt(s1.substring(0, 2));
            
            System.out.println(ans1 + "%");
        
        if(y==1000)
            System.out.println(100 + "%");
        else 
            String s2 = String.valueOf(y);
            int c2 = s2.charAt(2) - '0';
            if (c2 >= 5) 
                ans2 = Integer.parseInt(s2.substring(0, 2)) + 1;
             else 
                ans2 = Integer.parseInt(s2.substring(0, 2));
            
            System.out.println(ans2 + "%");
        
    

试题G:回文日期

思路:枚举N+1天开始的所有日期,判断是否满足条件即可。细节很多,需要注意处理细节。

import java.util.Scanner;
import static java.time.Year.isLeap ;


public class Main 
    public static void main(String[] args) 
        Scanner input = new Scanner(System.in) ;
        int N = input.nextInt() ;

        for(int i=N+1;i<=99991231;i++)
            int d = i % 100 ;
            if(d>31)
                i += 68 ;
            
            if(i%10000>=13000)
                i += i / 10000 + 999 ;
            
            if(f1(i))
                System.out.println(i);
                break ;
            
        
        for(int i=N+1;i<=99991231; i++)
            int d = i % 100 ;
            if(d>31)
                i += 68 ;
            
            if(i%10000>=13000)
                i += i / 10000 + 999;
            
            if(f1(i) && f2(i))
                System.out.println(i);
                break ;
            
        
    
    public static boolean f1(int i)
        String s = String.valueOf(i) ;
        int month = Integer.parseInt(s.substring(4,6)) ;
        int day = Integer.parseInt(s.substring(6,8)) ;
        if(month==0 || day==0)
            return false ;
        
        if(month>12 || day>31)
            return false ;
        
        if(month==4 || month==6 || month==9 || month==11 )
            if(day>30)
                return false ;
            
        
        if(isLeap(Integer.parseInt(s.substring(0,4))))
            if(day>29)
                return false ;
            
        else
            if(day>28)
                return false ;
            
        
        if(!isPalindrome(s))
            return false ;
        
        return true ;
     

    private static boolean isPalindrome(String s) 
        for(int i=0; i<s.length(); i++)
            if(s.charAt(i) != s.charAt(s.length()-1-i))
                return false ;
            
        
        return true ;
    

    public static boolean f2(int i)
        String s = String.valueOf(i) ;
        if(s.charAt(0)==s.charAt(2) && s.charAt(2) == s.charAt(5) && s.charAt(7)==s.charAt(5))
            if(s.charAt(1)==s.charAt(3) && s.charAt(3) == s.charAt(4) && s.charAt(4)==s.charAt(6))
                if(s.charAt(0) != s.charAt(1))
                    return true ;
                
            
        
        return false ;
    

试题H:作物杂交

思路:记忆化搜索,ans数组记忆已经得到的结果,vis数组标记当前作物是否已经生成,如果目标种子没有合成,遍历当前所有已有的杂交组合,对于合成值等于target的,递归计算两个合成target值得种子分别合成所需要得最大值。求出所有可能得最小值即是答案。AC代码如下:


import java.util.Scanner;

public class Main 
    static int N, M, K, T ;
    static int [][] hby ;
    static int [] time ;
    static int [] seed ;
    static int [] maxTime ;
    static int [] vis ;
    static int [] ans ;
    public static void main(String[] args) 
        Scanner input = new Scanner(System.in) ;
        N = input.nextInt() ;
        M = input.nextInt() ;
        K = input.nextInt() ;
        T = input.nextInt() ;
        time = new int [N+1] ;
        seed = new int [M] ;
        hby = new int [K][3] ;
        maxTime = new int [K] ; //记录两两杂交的最大时间
        vis = new int [N+1] ;
        ans = new int [N+1] ;


        for(int i=1; i<=N; i++)
            time[i] = input.nextInt() ;
        
        for(int i=0; i<M; i++)
            seed[i] = input.nextInt() ;
            vis[seed[i]] = 1 ; //记录作物已经合成
        

        for(int i=0; i<K; i++)
            hby[i][0] = input.nextInt() ;
            hby[i][1] = input.nextInt() ;
            hby[i][2] = input.nextInt() ;
            maxTime[i] = Math.max(time[hby[i][0]], time[hby[i][1]]) ;
        
        System.out.println(dfs(T));
    

    private static int  dfs(int target) 
        if(vis[target]!=1)
            int min = Integer.MAX_VALUE ;
            for(int i=0; i<K; i++)
                if(hby[i][2]==target)
                    min = Math.min(min, maxTime[i] + Math.max(dfs(hby[i][0]), dfs(hby[i][1]))) ;
                
            
            vis[target] = 1 ;
            ans[target] = min ;
            return min ;
        else
            return ans[target] ;
        
    

试题I:子串分值

思路1:枚举+HashMap记录,枚举所有可能,Map记录每个出现1次的字符,统计个数。可以通过部分测试用例,拿到10分+没问题。

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


public class Main 
    public static void main(String[] args) 
        Scanner input = new Scanner(System.in) ;
        String s = input.next() ;
        long ans = 0 ;
        for(int i=0; i<s.length(); i++)
            for(int j=i+1; j<=s.length(); j++)
               ans += f(s.substring(i,j));
                
            
        System.out.println(ans);
    
    public static long f(String s)
        long sum = 0 ;
        Map<Character, Integer> map = new HashMap<>() ;
        for(int i=0; i<s.length(); i++)
            map.put(s.charAt(i), map.getOrDefault(s.charAt(i), 0) + 1) ;
        
        for(char c : map.keySet())
            if(map.get(c)==1)
                sum ++ ;
            
        
        return sum ;
    

思路2:AC代码,动态规划思想,dp[i]表示以i结尾的字符串中的每个字符的贡献值,place数组记录每个字符上一次出现的位置,ans记录当前字符的贡献值,sum为所有字符的贡献值,每一次更新dp[c]和place[c].


import java.util.*;

public class Main1 
    static int ans, sum ;
    static int [] dp ;
    static int [] place ;
    public static void main(String[] args) 
        Scanner input = new Scanner(System.in) ;
        String s = input.next() ;
        dp = new int [26] ; //dp[i]表示以i结尾的字符串中每个字符的贡献值
        place = new int [26] ; //记录每个字符出现的位置

        Arrays.fill(place, -1) ;

        for(int i=0; i<s.length(); i++)
            int c = s.charAt(i) - 'a' ;
            ans += i - place[c] - dp[c] ;
            sum += ans ;
            dp[c] = i - place[c] ;
            place[c] = i ;
        
        System.out.println(sum);
    


试题J:装饰珠

参考链接:算法练习题27---蓝桥杯2020省赛“装饰珠”_杨大熊的代码世界的博客-CSDN博客_蓝桥杯 装饰珠

以上是关于第十一届蓝桥杯大赛软件类省赛Java研究生组-题解的主要内容,如果未能解决你的问题,请参考以下文章

第十一届蓝桥杯大赛软件类省赛第二场C/C++大学B组(python解答)

2020 第十一届蓝桥杯大赛软件赛省赛(第一场),C/C++大学B组题解

2022 第十三届蓝桥杯大赛软件赛省赛,C/C++ 大学B组题解

2022 第十三届蓝桥杯大赛软件赛省赛(第二场),C/C++ 大学B组题解

2020 第十一届蓝桥杯大赛软件赛省赛(第二场),C/C++大学B组题解

第十四届蓝桥杯大赛软件组省赛 Python大学A组 个人暴力题解