ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

【2021年蓝桥杯Java-B组省赛(第二场)题解】

2022-02-28 18:58:00  阅读:217  来源: 互联网

标签:Java scan int 题解 蓝桥 static ans new public


2021Java-B组省赛(第二场)

一、求余(水)

在 C / C + + / J a v a / P y t h o n 等 语 言 中 , 使 用 % 表 示 求 余 , 请 问 2021 % 20 的 值 是 多 少 ? 在 C/C++/Java/Python 等语言中,使用\%表示求余,请问 2021 \%20 的值是多少? 在C/C++/Java/Python等语言中,使用%表示求余,请问2021%20的值是多少?

答案:1

二、双阶乘(水)

在这里插入图片描述
只要最后五位,取余就行。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        long ans = 1;
        for (int i = 3; i <= 2021; i++) {
            if (i % 2 == 1) {
                ans = ans * i % 100000;
            }
        }
        System.out.println(ans);
    }
}

答案:59375

三、格点(水)

在这里插入图片描述
第一象限的格点,就是x > 0 且 y > 0 且x、y都是整数,穷举。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        int ans = 0;
        for (int i = 1; i <= 2021; i++) {
            for (int j = 1; j <= 2021; j++) {
                if (i * j <= 2021) ans++;
                else break;
            }
        }
        System.out.println(ans);
    }
}

答案:15698

四、整数分解(剪枝优化)

在这里插入图片描述
相同数字不同位置算作不同分解方法,暴力要优化一下。对于一个大于2的正整数n,如果拆分成俩个正整数(不同位置算不同方案),可以拆出n - 1种方式。

所以,我们只需要遍历前3个数即可,后2个数可以直接判断。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        long ans = 0;
        for (int i = 1; i <= 2021; i++) {
            for (int j = 1; j <= 2021; j++) {
                if (i + j >= 2021) {
                    break;
                }
                for (int k = 1; k <= 2021; k++) {
                    // 剪枝优化
                    int tmp = 2021 - i - j - k;
                    if (tmp > 2) {
                        ans += tmp - 1;
                    } else {
                        break;
                    }
                }
            }
        }
        System.out.println(ans);
    }
}

答案:691677274345

五、城邦(最小生成树)

在这里插入图片描述
第一场考的最短路径,第二场考的最小生成树,有点意思哈哈哈哈哈。

import java.util.*;

public class main {
    public static void main(String args[]) {
        // 依次编号从1 - 2021
        List<int[]>edges = new LinkedList<>();
        // 存边
        for (int i = 1; i <= 2021; i++) {
            for (int j = i + 1; j <= 2021; j++) {
                edges.add(new int[]{i, j, getNum(i, j)});
            }
        }
        // 记得给边排序!
        Collections.sort(edges, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[2] - o2[2];
            }
        });
        // 并查集
        class UF {
            // 连通分量个数
            int count;
            // 保存每棵树
            int[] parent;
            // 保存每棵树的大小
            int[] size;
            // 构造函数
            UF(int n) {
                this.count = n;
                this.parent = new int[n];
                this.size = new int[n];
                // 初始化
                for (int i = 0; i < n; i++) {
                    parent[i] = i;
                    size[i] = 1;
                }
            }
            // 找x的根节点
            public int find(int x) {
                while (parent[x] != x) {
                    parent[x] = parent[parent[x]];
                    x = parent[x];
                }
                return x;
            }
            // 判断是否相连
            public boolean connected(int p, int q) {
                return find(p) == find(q);
            }
            // 连通两个节点
            public void union(int p, int q) {
                int rootP = find(p);
                int rootQ = find(q);
                // 已经相连
                if (rootP == rootQ) return;
                // 小树连在大树下
                if (size[rootP] > size[rootQ]) {
                    parent[rootQ] = rootP;
                    size[rootP] += size[rootQ];
                } else {
                    parent[rootP] = rootQ;
                    size[rootQ] += size[rootP];
                }
                // 连通分量--
                count--;
            }
            // 返回连通分量个数
            public int count() {
                return count;
            }
        }
        // 从1 - 2021
        UF uf = new UF(2022);
        int mst = 0;
        for (int[] node : edges) {
            if (uf.connected(node[0], node[1])) continue;
            uf.union(node[0], node[1]);
            mst += node[2];
        }
        // 注意节点0不会用到,所以剩余的连通分量应该 = 2
        if (uf.count() == 2) {
            System.out.println(mst);
        } else {
            System.out.println(-1);
        }
    }
    public static int getNum(int m, int n) {
        int sum = 0;
        while (m != 0 || n != 0) {
            if (m % 10 != n % 10) {
                sum += m % 10;
                sum += n % 10;
            }
            m /= 10;
            n /= 10;
        }
        return sum;
    }
}

答案:4046

一定要掌握最小生成树和最短路径问题的模板,这种题目只要会模板就是送分的。最小生成树需要建边,需要给边按照权值从小到大排序。最短路径需要建图,需要遍历当前节点相邻的节点。

六、特殊年份(水)

在这里插入图片描述

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int ans = 0;
        for (int i = 0; i < 5; i++) {
            int year = scan.nextInt();
            String str = Integer.toString(year);
            if (str.charAt(0) == str.charAt(2) && str.charAt(3) - str.charAt(1) == 1) {
                ans++;
            }
        }
        System.out.println(ans);
    }
}

七、小平方(水)

在这里插入图片描述
需要注意的是整数除法,5 / 2 = 2,但实际=2.5,所以得往3考虑,要进行四舍五入。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        int ans = 0;
        for (int i = 1; i <= n - 1; i++) {
            double tmp = n * 1.0 / 2;
            int s = (int)(tmp + 0.5);
            if ((i * i) % n < s) {
                ans++;
            }
        }
        System.out.println(ans);
    }
}

八、完全平方数(数学定理)

在这里插入图片描述
又是这种大规模数据的数论题目,不能硬来。对于完全平方数而言,它的质因子的指数为偶数(不考虑1),质因子:1 2 3 5 7 11 13 17 19 23… 4 = 2 * 2,9 = 3 * 3,16 = 2 * 2 * 2 * 2,25 = 5 * 5,都是质因子的偶数幂。

质数又称素数。一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做质数;否则称为合数(规定1既不是质数也不是合数)。质因子的意思就是素数因子。

把一个合数用质因数相乘的形式表示出来,叫做分解质因数。质因子是不含1的。

质因子分解代码

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        // 从最小素数开始
        int k = 2;
        while (k * k <= n) {
            if (n % k == 0) {
                System.out.printf("%d", k);
                n /= k;
                System.out.println();
            } else {
                k++;
            }
        }
    }
}

这里不需要对k是否为质数进行check,直接除,每次输出的一定是质数。

36 = 2 * 2 * 3 * 3,对于一个完全平方数,它的质因数的指数总是个偶数,遍历所有质因子,将指数为奇数的质因子累乘起来,再与n相乘,这样就保证了所有的质因子的指数为偶数,那就一定是完全平方数,且是最小的。

非质数,即合数,一定可以进行质因子分解,其中每个质因子的指数为偶数的,为完全平方数。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        long n = scan.nextLong();
        long res = 1;
        // 只需要考虑到根号n即可
        for (long i = 2; i * i <= n; i++) {
            if (n % i == 0) {
                int cnt = 0;
                while (n % i == 0) {
                	// n也是跟着除的
                    n /= i;
                    cnt++;
                }
                // 累乘指数为奇数的质因子
                if (cnt % 2 == 1) {
                    res *= i;
                }
            }
        }
        // n为质数时,res=1,满足
        System.out.println(res * n);
    }
}

上面的解法就是为了保证,当前数的所有质因子的指数为偶数,不是偶数就再乘个该质因子。

九、负载均衡(模拟 + 优先队列(堆))

在这里插入图片描述
在这里插入图片描述
说实话,题目越长,越简单(开玩笑~)

直接模拟,用优先队列,也就是所谓的堆去存储一个个节点,这个节点存储着当前任务的结束时刻,和恢复体力值,考虑到有多个计算机,应该要用优先队列数组进行存储。

再次强调Java中使用System.out.println速度过慢的问题,改用BufferedWriter,打印的时候将输出内容转换为String类型即可。

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

// 记录当前计算机中任务的结束时刻,和恢复体力值
class node{
    int reHour;
    int health;
    node(){};
    node(int reHour, int health) {
        this.reHour = reHour;
        this.health = health;
    }
}
public class Main {
    // 加快打印速度
    static BufferedWriter log = new BufferedWriter(new OutputStreamWriter(System.out));
    public static void main(String args[]) throws IOException {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        int m = scan.nextInt();
        // 运算能力
        int[] com = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            com[i] = scan.nextInt();
        }
        // 构建优先队列
        Queue<node>[] pq = new PriorityQueue[n + 1];
        for (int i = 0; i < n + 1; i++) {
            pq[i] = new PriorityQueue<>(new Comparator<node>() {
                @Override
                // 按照恢复时间从小到大排序
                public int compare(node o1, node o2) {
                    return o1.reHour - o2.reHour;
                }
            });
        }
        int a, b, c, d;
        for (int i = 0; i < m; i++) {
            // 第 i 个任务在 ai 时刻分配,指定计算机编号为 bi,耗时为 ci 且算力消耗为 di
            // 如果此任务成功分配,将立刻开始运行,期间持续占用 bi 号计算机 di 的算力,持续 ci 秒
            a = scan.nextInt();
            b = scan.nextInt();
            c = scan.nextInt();
            d = scan.nextInt();
            // 注意任务执行完,算力是可以恢复的
            while (!pq[b].isEmpty()) {
                node tmp = pq[b].peek();
                if (tmp.reHour <= a) {
                    com[b] += tmp.health;
                    pq[b].poll();
                } else {
                    break;
                }
            }
            if (com[b] < d) {
                log.write(-1 + "");
                log.write("\n");
            } else {
                // 消耗计算机算力
                com[b] -= d;
                // 入队
                pq[b].offer(new node(a + c, d));
                log.write(com[b] + "");
                log.write('\n');
            }
        }
        log.flush();
    }
}

十、国际象棋(状压DP)

在这里插入图片描述
在这里插入图片描述
这种数据量下,不是数学规律就是DP,搜索时间不够。

本题作为DFS搜索练习题,也是极为不错的,有很多坑点。

import java.util.Scanner;

public class Main {
    static int MOD = 1000000007;
    static int ans = 0;
    static int n, m, k;
    // 方向数组
    static int[] xx = new int[] {1, 1, -1, -1, 2, 2, -2, -2};
    static int[] yy = new int[] {2, -2, 2, -2, 1, -1, 1, -1};
    static int[][] cnt;
    // 是否有马
//    static boolean[][] vis; 不能用vis数组来标记不能放马的位置,因为棋盘上某一点可能有多个马共同进行限制,需要对限制数计数
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        n = scan.nextInt();
        m = scan.nextInt();
        k = scan.nextInt();
        cnt = new int[n][m];
        // 从左上角第一个格子开始放,初始已放马的个数 = 0
        dfs(0, 0, 0);
        System.out.println(ans);
    }
    static void dfs (int x, int y, int horse) {
        if (horse == k) {
            ans = (ans + 1) % MOD;
            return;
        }
        // 切换到下一行第一个元素
        if (y >= m) {
            y = 0;
            x++;
            if (x >= n) return;
        }
        // 当前(x,y)位置不放马
        dfs(x, y + 1, horse);

        // 当前(x,y)位置放马
        // 先判断能否放马
        if (cnt[x][y] == 0) {
            cnt[x][y]++;
            // 遍历当前位置的马能够跳到的棋盘位置,标记为true
            for (int i = 0; i < 8; i++) {
                int tmpx = x + xx[i];
                int tmpy = y + yy[i];
                if (tmpx < 0 || tmpy < 0 || tmpx >= n || tmpy >= m) {
                    continue;
                }
                cnt[tmpx][tmpy]++;
            }
            // 放了马之后继续遍历
            dfs(x, y + 1, horse + 1);
            // 别忘了回溯
            // 回溯:一切在之前change过的变量,全都要恢复
            cnt[x][y]--;
            for (int i = 0; i < 8; i++) {
                int tmpx = x + xx[i];
                int tmpy = y + yy[i];
                if (tmpx < 0 || tmpy < 0 || tmpx >= n || tmpy >= m) {
                    continue;
                }
                cnt[tmpx][tmpy]--;
            }
        }
    }
}

回归正解:状压DP

状压DP还在修炼中…待更

标签:Java,scan,int,题解,蓝桥,static,ans,new,public
来源: https://blog.csdn.net/Mxeron/article/details/123021102

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有