2019第十届蓝桥杯省赛JavaA组题解

第十届蓝桥杯省赛JavaA组题解

试题 A: 平方和 本题总分:5 分

【问题描述】

小明对数位中含有 2、0、1、9 的数字很感兴趣,在 1 到 40 中这样的数包 括 1、2、9、10 至 32、39 和 40,共 28 个,他们的和是 574,平方和是 14362。 注意,平方和是指将每个数分别平方后求和。

请问,在 1 到 2019 中,所有这样的数的平方和是多少?

思路

转换成string再判断,使用bigInteger 保证不溢出

答案:2658417853

   public  static  boolean hasChar(String s){
        char[] chars=s.toCharArray();
        for (int i = 0; i <chars.length ; i++) {
            if(chars[i]=='2'||chars[i]=='0'||chars[i]=='1'||chars[i]=='9'){
                return true;
            }
        }
        return false;
    }
    public static void main(String[] args) {
        BigInteger res=new BigInteger("0");
        for (int i = 1; i <= 2019; i++) {
            String s=String.valueOf(i);
            if(hasChar(s)){
                BigInteger temp=new BigInteger(s);
                res=res.add(temp.multiply(temp));
            }

        }
        System.out.println(res);
    }

试题 B: 数列求值

本题总分:5 分

【问题描述】

给定数列 1, 1, 1, 3, 5, 9, 17, …,从第 4 项开始,每项都是前 3 项的和。求 第 20190324 项的最后 4 位数字。

思路:

  1. 求和

    斐波那契数列的小变形

  2. 求最后四位数字

    模10000

答案:4659

  1. 使用递归,数字太大直接栈溢出了

     public static  int fib(int flag,int one, int two ,int three){
            if(flag==1){
                return one;
            }
            else if(flag==2){
                return two;
            }
            else if( flag==3){
                return three;
            }
            else {
                return fib(flag-1,two%10000,three%10000,(one+two+three)%10000);
            }
    
        }
        public static void main(String[] args) {
            System.out.println(fib(20190324,1,1,1));
        }
    
  2. 不使用递归

      public static void main(String[] args) {
           // System.out.println(fib(201903,1,1,1));
            int one=1;
            int two=1;
            int three=1;
            int res=0;
            for (int i = 3; i <20190324 ; i++) {
                res=(one+two+three)%10000;
                one=two%10000;
                two=three%10000;
                three=res;
            }
            System.out.println(res);
        }
    

    试题 C: 迷宫 *

    本题总分:10 分

    【问题描述】

    下图给出了一个迷宫的平面图,其中标记为 1 的为障碍,标记为 0 的为可 以通行的地方。

    010000
    000100
    001001
    110000
    

    迷宫的入口为左上角,出口为右下角,在迷宫中,只能从一个位置走到这 个它的上、下、左、右四个方向之一。

    对于上面的迷宫,从入口开始,可以按DRRURRDDDR 的顺序通过迷宫, 一共 10 步。其中 D、U、L、R 分别表示向下、向上、向左、向右走。

    对于下面这个更复杂的迷宫(30 行 50 列),请找出一种通过迷宫的方式, 其使用的步数最少,在步数最少的前提下,请找出字典序最小的一个作为答案。 请注意在字典序中D<L<R<U。(如果你把以下文字复制到文本文件中,请务 必检查复制的内容是否与文档中的一致。在试题目录下有一个文件 maze.txt, 内容与下面的文本相同)

思路:

  1. 顺序 下 左 右 上
  2. 暂时不会

答案:

  class Node {
        int step;
        String path;
        int x, y;

        public Node(int step, String path, int x, int y) {
            super();
            //步数
            this.step = step;
            //路径
            this.path = path;
            this.x = x;
            this.y = y;
        }
    }

    public class Q3 {
        static Scanner in = new Scanner(System.in);
        static int n, m;
        static char[][] maze = new char[60][60];
        static boolean[][] vis = new boolean[60][60];
        //增量数组,方向向量,直接按字典序排列
        static int[] X = { 1, 0, 0, -1 };
        static int[] Y = { 0, -1, 1, 0 };
        static String[] d = { "D", "L", "R", "U" };

        public static void main(String[] args) throws FileNotFoundException {
            Scanner in = new Scanner(new File("/Users/pengzijun/Desktop/lanqiaoTraining/src/lq2019/maze.txt"));
            n = 30;
            m =50;
            //存入矩阵
            for (int i = 1; i <= n; ++i) {
                String temp = in.next();
                for (int j = 1; j <= m; ++j) {
                    maze[i][j] = temp.charAt(j - 1);
                }
            }
            bfs();
        }

        static boolean check(int x, int y) {
            if (x < 1 || x > n || y < 1 || y > m)
                //不在范围内
                return false;
            if (vis[x][y] || maze[x][y] == '1')
                //已经访问过或者是墙
                return false;
            return true;
        }

        static void bfs() {
            Queue<Node> q = new LinkedList<Node>();
            //offer 与add在有限制的队列添加元素不抛出异常,而是返回false
            q.offer(new Node(0, "", 1, 1));
            while (!q.isEmpty()) {
                //头节点
                Node top = q.poll();
                //设置为已经访问
                vis[top.x][top.y] = true;
                if (top.x == n && top.y == m) {
                    //走到边界节点
                    System.out.println(top.step + " " + top.path);
                    return;
                }
                for (int i = 0; i < 4; ++i) {
                    int newX = top.x + X[i];
                    int newY = top.y + Y[i];
                    if (check(newX, newY)) {
                        //把可以走的邻近节点都加进去
                        Node temp = new Node(top.step + 1, top.path + d[i], newX, newY);
                        q.offer(temp);
                    }
                }
            }
        }

}

试题 D: 最大降雨量

本题总分:10 分

【问题描述】

由于沙之国长年干旱,法师小明准备施展自己的一个神秘法术来求雨。

这个法术需要用到他手中的 49 张法术符,上面分别写着 1 至 49 这 49 个 数字。法术一共持续 7 周,每天小明都要使用一张法术符,法术符不能重复使 用。

每周,小明施展法术产生的能量为这周 7 张法术符上数字的中位数。法术 施展完 7 周后,求雨将获得成功,降雨量为 7 周能量的中位数。 由于干旱太久,小明希望这次求雨的降雨量尽可能大,请大最大值是多少?

思路:

不用编码,直接找规律

在这里插入图片描述

答案:34

试题 E: RSA 解密 *

本题总分:15 分

【问题描述】

RSA 是一种经典的加密算法。它的基本加密过程如下。首先生成两个质数 p, q,令 n = p · q,设 d 与 (p − 1) · (q − 1) 互质,则可 找到 e 使得 d · e 除 (p − 1) · (q − 1) 的余数为 1。

n, d, e 组成了私钥,n, d 组成了公钥。

当使用公钥加密一个整数 X 时(小于 n),计算 C = X**d 密后的密文。

当收到密文 C 时,可使用私钥解开,计算公式为 X = C**e 例如,当 p = 5, q = 11, d = 3 时,n = 55, e = 27。 若加密数字 24,得 243 mod 55 = 19。解密数字 19,得 1927 mod 55 = 24。

mod n,则 C 是加 mod n

现在你知道公钥中 n = 1001733993063167141, d = 212353,同时你截获了 别人发送的密文 C = 20190324,请问,原文是多少?

思路

暂时不会

矩阵快速乘、快速幂

答案

/*
java 大数转为long,记得后面最后面那个是l/L
 */

    static long n = 1001733993063167141L;
    static long d = 212353;
    static long c = 20190324;
    static long p = 2;
    static long q = 0;
    static long phi;
    static long e = 1;
    static long x1 = 0, y1 = 0;
    static long ans = 1;

    /**
    求解p和q的
     */
    public static void qiue() {
        while (n % p != 0) {
            p++;
        }
        q = n / p;
    }


    public static long quickmod(long a, long b) {
        long x = 0;
        while (b != 0) {
            if (b % 2 == 1) {
                x = (x + a) % n;
            }
            a = (a + a) % n;
            b /= 2;
        }
        return x;
    }
    //  用快速幂求模,每次求模后余数相乘,得到最后的答案
    //  每当要用到乘法时,用快速乘,再模,求余数

    public static void quickmul(long c, long e) {
        while (e != 0) {
            if (e % 2 == 1) {
                ans = quickmod(ans, c);
            }
            e /= 2;
            c = quickmod(c, c);
        }
    }


    public static void gcd(long i, long j, long a, long b) {   
        //欧几里得扩展求乘法逆元
        if (j == 0) {
            x1 = 1;
            y1 = 0;
            return;
        }

        gcd(j, i % j, x1, y1);
        long temp = x1;
        x1 = y1;
        y1 = temp - i / j * y1;
        e = x1;
        return;

    }


    public static void main(String[] args) {
        //求解p、q
        qiue();
        phi = (p - 1) * (q - 1);
        gcd(d, phi, x1, y1);
        e = (e + phi) % phi;
        quickmul(c, e);
        System.out.print(ans);

    }

参考:https://www.cnblogs.com/ohuo/p/12238049.html

试题 F: 完全二叉树的权值

时间限制: 1.0s 内存限制: 512.0MB 本题总分:15 分

【问题描述】

给定一棵包含 N 个节点的完全二叉树,树上每个节点都有一个权值,按从 上到下、从左到右的顺序依次是 A1, A2, · · · A**N,如下图所示:

在这里插入图片描述

现在小明要把相同深度的节点的权值加在一起,他想知道哪个深度的节点 权值之和最大?如果有多个深度的权值和同为最大,请你输出其中最小的深度。

注:根的深度是 1。

思路:

  1. 使用bigInteger防止溢出
  2. 完全二叉树,第n层的节点数为2^(n-1)

答案:

 public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        int n = s.nextInt();
        int[] nums = new int[n];
        for (int i = 0; i < n; i++) {
            nums[i] = s.nextInt();
        }
        //最大权值和
        BigInteger max = new BigInteger("0");
        //当前权值和
        BigInteger cur = new BigInteger("0");
        //深度
        int depth= 1;
        int index = 0;
        for (int i = 1; i <= n; i++) {
            cur = cur.add(new BigInteger(String.valueOf(nums[i - 1])));
            if (i == Math.pow(2, depth) - 1) {
                //当前节点为本层最后一个
                if (cur.compareTo(max) == 1) {
                    //当前层权值和大于最大值
                    max = cur;
                    index = depth;

                }
                //当前层权值归零,计算下层
                cur = new BigInteger("0");
                //层数加一
                depth++;

            }
        }
        System.out.println(index);
    }

试题 G: 外卖店优先级

时间限制: 1.0s 内存限制: 512.0MB 本题总分:20 分

【问题描述】

“饱了么”外卖系统中维护着 N 家外卖店,编号 1 ∼ N。每家外卖店都有 一个优先级,初始时 (0 时刻) 优先级都为 0。

每经过 1 个时间单位,如果外卖店没有订单,则优先级会减少 1,最低减 到 0;而如果外卖店有订单,则优先级不减反加,每有一单优先级加 2。

如果某家外卖店某时刻优先级大于 5,则会被系统加入优先缓存中;如果 优先级小于等于 3,则会被清除出优先缓存。

给定 T 时刻以内的 M 条订单信息,请你计算 T 时刻时有多少外卖店在优 先缓存中。

【输入格式】

第一行包含 3 个整数 NMT。以下 M 行每行包含两个整数 tsid,表示 ts 时刻编号 id 的外卖店收到

一个订单。

【输出格式】

输出一个整数代表答案。

【样例输入】

266 11 52 31 62 21 62

【样例输出】

1

【样例解释】

6 时刻时,1 号店优先级降到 3,被移除出优先缓存;2 号店优先级升到 6, 加入优先缓存。所以是有 1 家店 (2 号) 在优先缓存中。

【评测用例规模与约定】

对于 80% 的评测用例,1 ≤ N, M, T ≤ 10000。 对于所有评测用例,1 ≤ N,M,T ≤ 100000,1 ≤ tsT,1 ≤ idN

思路:

用二维数组存储1-t时刻,各个店铺的优先值

arrayList模拟优先缓存

答案:

 public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        int N = s.nextInt();
        int M = s.nextInt();
        int T = s.nextInt();
        Map<Integer, Integer> data = new TreeMap<Integer, Integer>();
        //res[i][j] 表示i时刻 j店铺的优先值
        int[][] res = new int[T + 1][N + 1];
        int[] ids = new int[M];
        int[] ts = new int[M];
        for (int i = 0; i < M; i++) {
            int key = s.nextInt();
            int value = s.nextInt();
            res[key][value] += 2;

        }
        int count = 0;
        ArrayList<Integer> arrayList=new ArrayList<>();
        for (int i = 1; i < T + 1; i++) {
            for (int j = 1; j < N + 1; j++) {
                if (res[i][j] == 0) {
                    //当前时刻没有订单,优先值-1,最少为0
                    res[i][j] = (res[i - 1][j] - 1) > 0 ? (res[i - 1][j] - 1) : 0;
                    if (res[i][j] <= 3) {
                        //踢出队列
                        if(arrayList.contains(j)){
                          //店铺在队列中则踢出
                            arrayList.remove((Object)j);
                        }
                    }

                }
                else {
                    //当前时刻有订单,累加
                    res[i][j] += res[i - 1][j];
                    if (res[i][j] > 5) {
                        //加入队列
                        if(!arrayList.contains(j)){
                            arrayList.add(j);
                        }
                       
                    }
                }

            }

        }
        System.out.println(arrayList.size());

    }

试题 H: 修改数组

时间限制: 1.0s 内存限制: 512.0MB 本题总分:20 分

【问题描述】

给定一个长度为 N 的数组 A = [A1, A2, · · · A**N ],数组中有可能有重复出现 的整数。

现在小明要按以下方法将其修改为没有重复整数的数组。小明会依次修改 A2,A3,··· ,A**N

当修改 A**i 时,小明会检查 A**i 是否在 A1 ∼ A**i−1 中出现过。如果出现过,则 小明会给 A**i 加上 1 ;如果新的 A**i 仍在之前出现过,小明会持续给 A**i 加 1 ,直 到 A**i 没有在 A1 ∼ A**i−1 中出现过。

A**N 也经过上述修改之后,显然 A 数组中就没有重复的整数了。 现在给定初始的 A 数组,请你计算出最终的 A 数组。

【输入格式】

第一行包含一个整数 N。 第二行包含N个整数A1,A2,··· ,A**N

【输出格式】

输出N个整数,依次是最终的A1,A2,··· ,A**N

【样例输入】

5 21134

【样例输出】

21345 【评测用例规模与约定】

对于 80% 的评测用例,1 ≤ N ≤ 10000。 对于所有评测用例,1 ≤ N ≤ 100000,1 ≤ A**i ≤ 1000000。

思路:

1 ≤ N ≤ 100000,开数组储存每个数出现的次数

答案:

   public static void main(String[] args) {
        Scanner s= new Scanner(System.in);

        int n=s.nextInt();
        int[] nums=new int[n+1];
        for (int i = 0; i <n ; i++) {
            int temp=s.nextInt();
            while(nums[temp]!=0){
                temp++;
            }
            nums[temp]++;
            System.out.print(temp+" ");
}
}

试题 I: 糖果*

时间限制: 1.0s 内存限制: 512.0MB 本题总分:25 分

【问题描述】

糖果店的老板一共有 M 种口味的糖果出售。为了方便描述,我们将 M 种 口味编号 1 ∼ M

小明希望能品尝到所有口味的糖果。遗憾的是老板并不单独出售糖果,而 是 K 颗一包整包出售。

幸好糖果包装上注明了其中 K 颗糖果的口味,所以小明可以在买之前就知 道每包内的糖果口味。

给定 N 包糖果,请你计算小明最少买几包,就可以品尝到所有口味的糖 果。

【输入格式】

第一行包含三个整数 NMK。接下来 N 行每行 K 这整数 T1, T2, · · · , T**K,代表一包糖果的口味。

【输出格式】

一个整数表示答案。如果小明无法品尝所有口味,输出 −1。

【样例输入】

6 5 3

1 1 2

1 2 3

1 1 3

2 3 5

5 4 2

5 1 2

【样例输出】

2

【评测用例规模与约定】

对于30%的评测用例,1 ≤ N ≤ 20。 对于所有评测样例,1≤N≤100,1≤M≤20,1≤K≤20,1≤T**iM

思路:

状态压缩动态规划

答案:

  static Scanner sc = new Scanner(System.in);
    static int[][] a = new int[105][25];
    static int[] sta = new int[105];
    static int[] dp = new int[(1<<20)+5];

    public static void main(String[] args) {

        int n=sc.nextInt();
        int m=sc.nextInt();
        int k=sc.nextInt();
        Arrays.fill(dp, -1);
        dp[0]=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=k;j++){
                a[i][j]=sc.nextInt();
                sta[i]|=1<<(a[i][j]-1);
            }
            dp[sta[i]]=1;
        }
        for(int i=1;i<=n;i++){
            for(int j=0;j<(1<<m);j++){
                if(dp[j]==-1) continue;
                if(dp[j|sta[i]]==-1||dp[j]+1<dp[j|sta[i]]){
                    dp[j|sta[i]]=dp[j]+1;
                }
            }
        }
        System.out.println(dp[(1<<m)-1]);
    }

试题 J: 组合数问题*

时间限制: 5.0s 内存限制: 512.0MB 本题总分:25 分

【问题描述】

n,m,k,求有多少对(i,j)满足1 ≤ in,0 ≤ jmin(i,m)且Cij ≡ 0(mod k),k 是质数。其中 Cij 是组合数,表示从 i 个不同的数中选出 j 个组成 一个集合的方案数。

【输入格式】

第一行两个数 t, k,其中 t 代表该测试点包含 t 组询问,k 的意思与上文中 相同。

接下来 t 行每行两个整数 n, m,表示一组询问。 【输出格式】

输出 t 行,每行一个整数表示对应的答案。由于答案可能很大,请输出答 案除以 109 + 7 的余数。

【样例输入】

12 33

【样例输出】

1

【样例说明】

在所有可能的情况中,只有 C21 = 2 是 2 的倍数。

【样例输入】

25

67

【样例输出】

0 7

【样例输入】

3 23
23333333 23333333 233333333 233333333 2333333333 2333333333

【样例输出】

851883128

959557926

680723120

【数据规模和约定】

对于所有评测用例,1 ≤ k ≤ 108, 1 ≤ t ≤ 105, 1 ≤ n, m ≤ 1018,且 k 是质数。 评测时将使用 10 个评测用例测试你的程序,每个评测用例的限制如下:

评测用例编号 t n,m k

思路:

卢卡斯定理,未接触过,不会

发布了36 篇原创文章 · 获赞 8 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_42297075/article/details/104333361