草庐IT

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

nuist__NJUPT 2023-10-02 原文

目录

试题A:卡片

试题B:相乘

试题C:直线

试题D:路径

试题E:回路计数

试题F:时间显示

试题G:最少砝码

试题H:杨辉三角

试题I:双向排序

试题J:分果果


试题A:卡片

答案:3181

思路:num数组记录0-9的个数,从1开始判断,如果数字的各位中含有字母c,则num[c]减1,直至最后num[c]<0,则不能凑出。

public class Main {
    public static void main(String[] args) {

        int [] num = {2021,2021,2021,2021,2021,2021,2021,2021,2021,2021} ;
        for(int i=1; ; i++){
            String s = String.valueOf(i) ;
            for(int j=0; j<s.length(); j++){
                int c = s.charAt(j) - '0' ;
                num[c] -- ;
                if(num[c]<0){
                    System.out.println(i-1);
                    return ;
                }
            }
        }
    }
}

试题B:相乘

答案:17812964

思路:枚举+判断即可。

public class Main {
    public static void main(String[] args) {

        for(long i=1; i<=1000000007; i++){
            if((i * 2021)%1000000007==999999999){
                System.out.println(i);
                return ;
            }
        }
        System.out.println(0);
    }
}

试题C:直线

答案:40257

思路:这题并不太容易想到,其实就是枚举所有点,判断对应的斜率和截距组成的不同坐标的个数,可以用set自动去重。

公式:y-y1=(y2-y1)/(x2-x1)*(x-x1)

故:k=(y2-y1) / (x2-x1) ; b=(x2*y1-x1*y2)/(x2-x1)


import java.util.Set;
import java.util.TreeSet;

public class Main {
    public static void main(String[] args) {
        Set<String> set = new TreeSet<>() ;
        double k, b ;
        for(int x1=0; x1<20; x1++){
            for(int y1=0; y1<=20; y1++){
                for(int x2=x1+1; x2<20; x2++){
                    for(int y2=0; y2<=20; y2++){
                        k = 1.0  * (y2 - y1) / (x2 - x1) ;
                        b = 1.0 * (x2 * y1 - x1 * y2) / (x2 - x1) ;
                        set.add(k+","+b) ;
                    }
                }
            }
        }
        System.out.println(set.size()+20); //要加上斜率不存在的20个
    }
}

试题D:路径

答案:10266837

思路:单源最短路径,Dijkstra算法,建立邻接表,如果节点之差绝对值小于等于21,建立边,对应的边权值为两节点值得最小公倍数,dist数组记录到达相应节点得最短路径,通过优先队列按照权值最小排序,每次选择更小得路径 ,更新当前路径。

import java.util.ArrayList;
import java.util.List;
import java.util.PriorityQueue;

public class Main{
    public static void main(String[] args) {
        List<int []> g[] = new List [2022] ;
        for(int i=0; i<2022; i++){
            g[i] = new ArrayList<>() ;
         }

        for(int i=1; i<=2020; i++){
            for(int j=i+1; j<=2021; j++){
                if(Math.abs(i-j)<=21){
                    g[i].add(new int [] {j, f(i,j)}) ;
                    g[j].add(new int [] {i, f(i,j)}) ;
                }
            }
        }
        int [] dist = new int [2022] ;
        for(int i=1; i<2022; i++){
            dist[i] = Integer.MAX_VALUE ;
        }
        dist[1] = 0 ;

        //优先队列,按权值进行升序排序
        PriorityQueue<int []> queue = new PriorityQueue<int[]>((a,b)->a[1]!=b[1] ? a[1] - b[1] : a[0] - b[0]) ;
        queue.add(new int[]{1,0}) ; //到达的节点和对应的权值
        while(!queue.isEmpty()){
            int [] p = queue.poll() ;
            int x = p[0], w = p[1] ;
            if(dist[x]<w){
                continue;
            }
            for(int [] edges : g[x]){
                int y = edges[0], d = dist[x] + edges[1]  ;
                if(d<dist[y]){
                    dist[y] = d ;
                    queue.add(new int [] {y, d}) ;
                }
            }
        }
        System.out.println(dist[2021]);


    }
    private static int f(int a, int b){
       return a * b /  gcd(a,b) ;
    }
    private static int gcd(int a, int b){
        if(b==0){
            return a ;
        }else{
            return gcd(b,a%b) ;
        }
    }
}

试题E:回路计数

答案:881012367360

思路:状压+dp,f[i][j]表示从1出发走到j且经过i得方案数,用二进制表示经过点的状态。

public class Main {
    static boolean [][] edges ;
    static int m = 1 << 21 ;
    static long [][] f ;
    public static void main(String[] args) {
        edges = new boolean [21][21] ;
        f = new long [m][21] ;
        for(int i=1; i<=21; i++){
            for(int j=1; j<=21; j++){
                if(gcd(i,j)==1){
                    edges[i-1][j-1] = true ;
                }
            }
        }

        f[1][0] = 1 ;
        for(int i=0; i<=m-1; i++){
            for(int j=0; j<=20; j++){
                if((i>>j & 1) != 0){
                    for(int k=0; k<=20; k++){
                        if((i-(1<<j)>>k & 1)!=0 && edges[k][j]){
                            f[i][j] += f[i-(1<<j)][k] ;
                        }
                    }
                }
            }
        }
        long ans = 0 ;
        for(int i=1; i<=20; i++){
            ans += f[m-1][i] ;
        }
        System.out.println(ans);

    }

    private static int gcd(int m, int n) {
        if(n==0){
            return m ;
        }else{
            return gcd(n, m%n) ;
        }
    }

}

试题F:时间显示

思路:模拟,将总毫秒数对一天的毫秒数取余,得到的time是剩余需要操作的毫秒数,计算出时分秒即可,如果是个位数,需要在前面补零。

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in) ;
        long t = input.nextLong() ;

        long ms = 24 * 60 * 60 * 1000 ;
        long time = t % ms ;

        long hour = time / 3600000 ;
        long min = (time % 3600000) / 60000 ;
        long sec = ((time%3600000) % 60000) / 1000 ;

        String h = String.valueOf(hour) ;
        String m = String.valueOf(min) ;
        String s = String.valueOf(sec) ;
        if(h.length()==1){
            h = "0" + h ;
        }
        if(m.length()==1){
            m = "0" + m ;
        }
        if(s.length()==1){
            s = "0" + s ;
        }

        System.out.println(h + ":" + m + ":" + s);
    }
}

试题G:最少砝码

思路:规律题,我们想使用最少的砝码称出任意小于等于N的正整数数量,我们用count记录 砝码个数,weight记录所需的最后一个砝码的重量,total记录砝码能称出的总重量,这样会发现weight每次应该乘以3,而total等于上一轮的toal加上这次的weight。

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in) ;
        int N = input.nextInt() ;
        int count = 1 ; //砝码个数
        int weight = 1 ; //最后一个砝码的重量
        int total = 1 ; //砝码能称出的总重量

        while(total<N){
            count ++ ;
            weight *= 3 ;
            total += weight ;
        }

        System.out.println(count);

    }
}

试题H:杨辉三角

思路:这题想AC,不太容易,很容易爆内存,那就先混分吧,开辟二维数组记录杨辉三角,然后转成一维数组,vis数组标记是否是第一次出现,index数组记录第一次出现的位置。

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in) ;
        int N = input.nextInt() ;
        int [][] a = new int [20][20] ;
        int [] ans = new int [100000000] ;
        int [] vis = new int [100000000] ;
        int [] index = new int [100000000] ;
        for(int i=0; i<20; i++){
            for(int j=0; j<=i; j++){
                if(i==j || j==0){
                    a[i][j] = 1 ;
                }else{
                    a[i][j] = a[i-1][j-1] + a[i-1][j] ;
                }
            }
        }

        int k = 0 ;
        for(int i=0; i<20; i++) {
            for (int j = 0; j <= i; j++) {
                ans[k++] = a[i][j] ;
                if(vis[a[i][j]]==0){
                    vis[a[i][j]] = 1 ;
                    index[a[i][j]] = k ;
                }
            }
        }
            System.out.println(index[N]);
    }
}

试题I:双向排序

思路:这题考的是线段树,对于混分大师来说,根据题意模拟双向排序就行。

import java.util.Arrays;
import java.util.Scanner;

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

        a = new int [n] ;

        for(int i=1; i<=n; i++){
            a[i-1] = i ;
        }

        for(int i=1; i<=m; i++){
            int p = input.nextInt() ;
            int q = input.nextInt() ;
            if(p==0) {
                desc(a,0,q-1);
            }else if(p==1){
                asc(a,q-1,n-1) ;
            }
        }
        for(int i=0; i<a.length; i++){
            System.out.print(a[i]+" ");
        }
    }

    private static void desc(int[] a, int begin, int end) {
        int [] ans = new int [end-begin+1] ;
        int j = 0 ;
        for(int i=begin; i<=end; i++){
            ans[j++] = a[i] ;
        }
        Arrays.sort(ans);
        j-- ;
        for(int i=begin; i<=end; i++){
            a[i] = ans[j--] ;
        }
    }

    private static void asc(int[] a, int begin, int end) {
        int [] ans = new int [end-begin+1] ;
        int j = 0 ;
        for(int i=begin; i<=end; i++){
            ans[j++] = a[i] ;
        }
        Arrays.sort(ans);
        j = 0 ;
        for(int i=begin; i<=end; i++){
            a[i] = ans[j++] ;
        }
    }
}

试题J:分果果

思路:有些难的动态规划了,思路可以参考这个:蓝桥杯 - 分果果 - SOSCHINA - 博客园

import java.io.*;
import java.util.*;

public class Main {

    public static void main(String[] args) { new Main().run(); }

    int INF = 0x3F3F3F3F;

    void run() {
        InputReader in = new InputReader(System.in);
        int n = in.readInt(), m = in.readInt(), ans = INF;
        int[][][] dp = new int[m + 1][n + 1][n + 1];
        int[] S = new int[n + 1];
        for (int i = 1; i <= n; i++)
            S[i] = S[i - 1] + in.readInt();
        for (int i = 0; i <= m; i++)
            for (int j = 0; j <= n; j++)
                for (int k = 0; k <= j; k++) dp[i][j][k] = INF;
        dp[0][0][0] = 0;
        for (int min = S[n] * 2 / m; min > 0; min--) {
            for (int i = 1; i <= m; i++)
                for (int j = 1; j <= n; j++) {
                    int trans2 = 0, trans3 = 0;
                    for (int k = 1; k <= j; k++) {
                        dp[i][j][k] = dp[i][j][k - 1];
                        while (trans2 < k && S[j] - S[trans2 + 1] >= min &&
                                max(dp[i - 1][trans2 + 1][trans2 + 1], S[j] - S[trans2 + 1]) <= max(dp[i - 1][trans2][trans2], S[j] - S[trans2])) trans2++;
                        if (S[j] - S[trans2] >= min)
                            dp[i][j][k] = min(dp[i][j][k], max(dp[i - 1][trans2][trans2], S[j] - S[trans2]));
                        while (trans3 < k && S[j] - S[trans3 + 1] >= min &&
                                max(dp[i - 1][k][trans3 + 1], S[j] - S[trans3 + 1]) <= max(dp[i - 1][k][trans3 + 1], S[j] - S[trans3])) trans3++;
                        if (S[j] - S[trans3] >= min)
                            dp[i][j][k] = min(dp[i][j][k], max(dp[i - 1][k][trans3], S[j] - S[trans3]));
                    }
                }
            ans = min(ans, dp[m][n][n] - min);
        }
        System.out.println(ans);
    }

    int max(int arg1, int arg2) { return arg1 > arg2 ? arg1 : arg2; }

    int min(int arg1, int arg2) { return arg1 < arg2 ? arg1 : arg2; }

    class InputReader {

        BufferedReader reader;
        StringTokenizer token;

        InputReader(InputStream in) {
            this.reader = new BufferedReader(new InputStreamReader(in));
        }

        String read() {
            while (token == null || !token.hasMoreTokens()) {
                try {
                    token = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return token.nextToken();
        }

        int readInt() { return Integer.parseInt(read()); }
    }
}

有关第十二届蓝桥杯大赛软件类省赛Java研究生组-题解的更多相关文章

  1. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  2. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  3. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  4. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  5. Observability:从零开始创建 Java 微服务并监控它 (二) - 2

    这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/

  6. 【Java 面试合集】HashMap中为什么引入红黑树,而不是AVL树呢 - 2

    HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候

  7. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

  8. java - 为什么 ruby​​ modulo 与 java/other lang 不同? - 2

    我基本上来自Java背景并且努力理解Ruby中的模运算。(5%3)(-5%3)(5%-3)(-5%-3)Java中的上述操作产生,2个-22个-2但在Ruby中,相同的表达式会产生21个-1-2.Ruby在逻辑上有多擅长这个?模块操作在Ruby中是如何实现的?如果将同一个操作定义为一个web服务,两个服务如何匹配逻辑。 最佳答案 在Java中,模运算的结果与被除数的符号相同。在Ruby中,它与除数的符号相同。remainder()在Ruby中与被除数的符号相同。您可能还想引用modulooperation.

  9. java - Ruby 相当于 Java 的 Collections.unmodifiableList 和 Collections.unmodifiableMap - 2

    Java的Collections.unmodifiableList和Collections.unmodifiableMap在Ruby标准API中是否有等价物? 最佳答案 使用freeze应用程序接口(interface):Preventsfurthermodificationstoobj.ARuntimeErrorwillberaisedifmodificationisattempted.Thereisnowaytounfreezeafrozenobject.SeealsoObject#frozen?.Thismethodretur

  10. java - Java 的 StringReader 的 Ruby 等价物是什么? - 2

    在Java中,可以像这样从一个字符串创建一个IO流:Readerr=newStringReader("mytext");我希望能够在Ruby中做同样的事情,这样我就可以获取一个字符串并将其视为一个IO流。 最佳答案 r=StringIO.new("mytext")和here'sthedocumentation. 关于java-Java的StringReader的Ruby等价物是什么?,我们在StackOverflow上找到一个类似的问题: https://st

随机推荐