第十五届蓝桥杯第二期模拟赛(史上最细)

1,以下内容皆为原创。

2,代码虽然用的是Java,但算法思想别无二致。

3,包含本次模拟赛10道题的思路,尽可能多的题解和代码注释

4,代码均为作者手敲,若有错误,优化其它解法,望留言,共同进步。


答案:108

解析:单纯的一道数学题,和语言没关系。30个36像素的字总共是30*36=1080。那变成10像素就是 1080/10=108 个字。 

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

        System.out.println(36*30/10);  //108

    }
}


答案:608

解析:这道题数值太大,所以我们每算出来一步,就要进行取余。 

public class Main {
    public static void main(String[] args) {
        int two=2;
        int ans=1;
        for (int i = 1; i <= 2023; i++) {
            ans=(ans*two)%1000;  //注意:这里对乘积的整体取余。
        }                        //若写成 ans*=two%1000 ,它只对two取余了,所以是错的。
        System.out.println(ans); //608
    }
}

答案:4169 

解析:本题考查高进制转低进制的一个经典之法--除基取余法。 

public class Main {
    public static void main(String[] args) {
        int cnt=1;
        int i=1;
        while(cnt<25){
            //十进制转二进制
            int temp2=i;
            int sum2=0;
            while (temp2>0){
                sum2+=temp2 % 2;
                temp2 /= 2;
            }
            //十进制转八进制
            int temp8=i;
            int sum8=0;
            while (temp8>0){
                sum8+=temp8 % 8;
                temp8 /= 8;
            }
            //判断二进制数位和与八进制数位和是否相等
            if(sum2==sum8) {
                System.out.print(cnt++ + "  ");
                System.out.println(i);
            }
            i++;
        }
    }
}

答案:901440

解析: 枚举,对每一个数的约数个数做统计,选出第一个最大的。

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int[][] arr = new int[6][6];
        for (int i = 0; i < 6; i++) {
            for (int j = 0; j < 6; j++) {
                arr[i][j]=sc.nextInt(); //将36个数读入数组中.
            }
        }
        int max=0;
        int maxNumber=0;
        for (int[] row : arr){
            for (int col : row){
                int ans = getCount(col);
                if(ans>max){   //严格大于才进去,保证是最先出现的最大数
                    max=ans;
                    maxNumber=col; //将最大数存起来
                }
            }
        }
        System.out.println(maxNumber);
    }
    public static int getCount(int n){
        int cnt=0;
        for (int i = 1; i <= n; i++) {  //枚举,统计约数.
            if(n%i==0) cnt++;
        }
        return cnt;
    }
}

 

答案:591

解析:这个题,题目读起来语义不明的感觉,我的理解是第一行和第一列上的所有0变成2。 方法很多,最重要的是写的代码要考虑连通性,这是很致命的。下面给大家给出深搜,广搜,递归解法。 

//深搜
public class Main {
    static final int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; // 定义上下左右四个方向的偏移量
    static int rows = 30;
    static int cols = 40;
    static int ans = 0;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int[][] matrix = new int[rows][cols];
        for (int i = 0; i < rows; i++) {
            String s = sc.next();    //这里不推荐使用nextLine()读取,因为它会读入空格,所以容易出错.
            for (int j = 0; j < cols; j++) {
                matrix[i][j] = Integer.parseInt(s.charAt(j)+""); //将字符串中单个字符提取出来变为数字添进数组中.
            }
        }
        //统计
        int twos = countTwos(matrix);
        System.out.println(twos);
    }
    public static int countTwos(int[][] matrix) {
        // 遍第一行,将值为0的元素及其相邻的0元素变为2
        for (int i = 0; i < cols; i++) {
            if (matrix[0][i] == 0) {
                dfs(matrix, 0, i);
            }
        }
        // 遍历第一列,将值为0的素及其相邻的0元素变为2
        for (int i = 0; i < rows; i++) {
            if (matrix[i][0] == 0) {
                dfs(matrix, i, 0);
            }
        }
        return ans;
    }

    private static void dfs(int[][] matrix, int row, int col) {
        // 标记当前位置为2
        matrix[row][col] = 2;
        ans++;
        // 遍历当前位置的上下左右四个相邻位置
        for (int[] dir : dirs) {
            int newRow = row + dir[0];
            int newCol = col + dir[1];
            // 判断新位置是否合法且为0,若是则递归调用dfs函数
            if (newRow >= 0 && newRow < rows && newCol >= 0 && newCol < cols && matrix[newRow][newCol] == 0) {
                dfs(matrix, newRow, newCol);
            }
        }
    }
}
//广搜
public class Main {
    static final int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; // 定义上下左右四个方向的偏移量
    static int rows = 30;
    static int cols = 40;
    static int ans = 0;  //累加统计

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int[][] matrix = new int[rows][cols];
        for (int i = 0; i < rows; i++) {
            String s = sc.next();    //这里不推荐使用nextLine()读取,因为它会读入空格,所以容易出错.
            for (int j = 0; j < cols; j++) {
                matrix[i][j] = Integer.parseInt(s.charAt(j)+""); //将字符串中单个字符提取出来变为数字添进数组中.
            }
        }
        int twos = countTwos(matrix);
        System.out.println(twos);
    }

    public static int countTwos(int[][] matrix) {
        boolean[][] vis = new boolean[rows][cols]; // 用于记录节点是否已经被处理过
        Queue<int[]> queue = new LinkedList<>(); // 创建队列
        // 遍历第一行
        for (int i = 0; i < cols; i++) {
            if (matrix[0][i] == 0) {
                queue.offer(new int[]{0, i}); // 将节点添加到队列中
                matrix[0][i] = 2; // 将节点的值改为2
                ans++;
                vis[0][i] = true; // 标记节点为已处理
            }
        }
        // 遍历第一列
        for (int i = 0; i < rows; i++) {
            if (matrix[i][0] == 0) {
                queue.offer(new int[]{i, 0});
                matrix[i][0] = 2;
                ans++;
                vis[i][0] = true;
            }
        }
        while (!queue.isEmpty()) {
            int[] curr = queue.poll(); // 弹出队列中的第一个节点
            int row = curr[0];
            int col = curr[1];
            // 检查上下左右四个方向的位置
            for (int[] dir : dirs) {
                int newRow = row + dir[0];
                int newCol = col + dir[1];
                // 如果位置合法且值为0且未被处理过,则将其添加到队列中,将其值改为2,并标记为已处理
                if (newRow >= 0 && newRow < rows && newCol >= 0 && newCol < cols && matrix[newRow][newCol] == 0 && !vis[newRow][newCol]) {
                    queue.offer(new int[]{newRow, newCol});
                    matrix[newRow][newCol] = 2;
                    ans++;
                    vis[newRow][newCol] = true;
                }
            }
        }
        return ans;
    }
}
//递归
public class Main{
    static int rows = 30; //行
    static int cols = 40; //列
    static int ans = 0;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int[][] matrix = new int[rows][cols];
        for (int i = 0; i < rows; i++) {
            String s = sc.next();    //这里不推荐使用nextLine()读取,因为它会读入空格,所以容易出错.
            for (int j = 0; j < cols; j++) {
                matrix[i][j] = Integer.parseInt(s.charAt(j)+""); //将字符串中单个字符提取出来变为数字添进数组中.
            }
        }
        // 遍历第一列,将值为0的素及其相邻的0元素变为2
        for (int i = 0; i < rows; i++) {
            if (matrix[i][0] == 0) {
                infect(matrix, i, 0);
            }
        }
        // 遍第一行,将值为0的元素及其相邻的0元素变为2
        for (int j = 0; j < cols; j++) {
            if (matrix[0][j] == 0) {
                infect(matrix, 0, j);
            }
        }
        System.out.println(ans);
    }

    // 递归函数,将当前位置的周围0全部变为2
    public static void infect(int[][] matrix, int i, int j) {
        if (i < 0 || i >= rows || j < 0 || j >= cols || matrix[i][j] != 0) {
            return;
        }
        matrix[i][j] = 2;
        ans++;
        infect(matrix, i-1, j); //上
        infect(matrix, i+1, j); //下
        infect(matrix, i, j-1); //左
        infect(matrix, i, j+1); //右
    }
}

解析:简单题,只需要想个方法,把第一个数放末尾就行。以下给出数位,数组,字符串的解题方法。 

//数位
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int number = sc.nextInt();  //读入一个六位数

        int digit1 = number / 100000; // 十万位
        int digit2 = (number / 10000) % 10; // 万位
        int digit3 = (number / 1000) % 10; // 千位
        int digit4 = (number / 100) % 10; // 百位
        int digit5 = (number / 10) % 10; // 十位
        int digit6 = number % 10; // 个位

        int result = digit2 * 100000 + digit3 * 10000 + digit4 * 1000 + digit5 * 100 + digit6 * 10 + digit1;

        System.out.println(result);
    }
}
//数组
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int number = sc.nextInt();  //读入一个六位数
        //依次存在数组里
        int[] arr = new int[6];
        for (int i = arr.length-1; i >=0; i--) {
            arr[i] = number % 10;
            number /= 10;
        }
        //把第一个拿出来放最后
        int temp=arr[0];
        for (int i = 1; i < arr.length; i++) {
            arr[i-1]=arr[i];   //依次往前挪移
        }
        arr[arr.length-1]=temp;
        //遍历
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i]);
        }
    }
}
//字符串
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.next();
        //截取第一个字符拼接在末尾
        String s1 = s.substring(0,1);
        String s2 = s.substring(1);
        System.out.println(s2+s1);
    }
}

解析:首先用正向思维解题,由于每个字符串里的元音字母个数不同,所以我们用集合这种变长容器来存取,然后拿到最后一个元音字母。然后用逆向思维解题,从后往前看,就很简单了。 

//有序集合
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String str = sc.next();
        //拿到最后一个元音字母
        char lastVowel = getLastVowel(str);
        System.out.println(lastVowel);
    }

    public static char getLastVowel(String str) {
        List<Character> vowels = new ArrayList<>();
        //依次遍历字符串,将元音字母存进有序集合.
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (isVowel(c)) {
                vowels.add(c);
            }
        }
        return vowels.get(vowels.size() - 1);
    }

    public static boolean isVowel(char c) {
        return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
    }
}
​//逆向遍历
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        //读入字符串放在字符数组中
        char[] s = sc.next().toCharArray();
        //逆向思维,从后往前看
        for (int i = s.length-1; i >=0 ; i--) { 
            if(s[i]=='a'||s[i]=='e'||s[i]=='i'||s[i]=='o'||s[i]=='u'){
                System.out.println(s[i]);
                break;
            }
        }
    }
}

​

解析: 将乘积用一个临时变量保存,再赋给自己,迭代自己,直到自己小于10.

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt(); //输入一个整数
        while(n>=10){
            int temp=n;
            int ans=1;
            while(temp>0){  //对临时变量进行数位乘积。
                int digit=temp%10;
                if(digit>0){
                    ans*=digit;
                }
                temp/=10;
            }
            System.out.println(ans);
            n=ans;  //把结果赋给本身,迭代自己。
        }
    }
}

 解析:这道题和第五题的思想很类似,也是一道最大连通的问题,只是这道题是求存在>1约数的最大连通。下面给出深搜和递归。

​//深搜
public class Main {
    private static int n; //行
    private static int m; //列
    private static int[][] grid;  //存储
    private static boolean[][] visited; //标记
    private static int answer; //统计

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        m = sc.nextInt();
        grid = new int[n][m];   
        visited = new boolean[n][m];  //此数组对走过的位置进行标记
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                grid[i][j] = sc.nextInt();
            }
        }
        int r = sc.nextInt();  //起始位置的行
        int c = sc.nextInt();  //起始位置的列
        dfs(r - 1, c - 1); //变成数组对应的位置开始深搜
        System.out.println(answer);
    }

    private static void dfs(int x, int y) {
        if (visited[x][y]) {
            return;
        }
        //标记,++
        visited[x][y] = true;
        answer++;
        //判断左 下 右 上是否有存在 >1 约数的,有则继续深搜。
        int[] dx = {-1, 0, 1, 0};
        int[] dy = {0, 1, 0, -1};
        for (int i = 0; i < 4; i++) {
            int nx = x + dx[i];
            int ny = y + dy[i];
            if (nx >= 0 && nx < n && ny >= 0 && ny < m && gcd(grid[x][y], grid[nx][ny]) > 1) {
                dfs(nx, ny);
            }
        }
        visited[x][y] = false;
    }

    //欧几里得算法
    private static int gcd(int a, int b) {
        if (b == 0) {
            return a;
        }
        return gcd(b, a % b);
    }
}

​
//递归
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();  //行
        int m = sc.nextInt();  //列
        int[][] grid = new int[n][m];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                grid[i][j] = sc.nextInt();  //向数组中读入元素
            }
        }
        int r = sc.nextInt();  //起始位置的行
        int c = sc.nextInt();  //起始位置的列
        boolean[][] visited = new boolean[n][m]; //标记是否被访问
        //递归调用并输出
        System.out.println(getCount(grid, r-1, c-1, visited));
    }
    public static int getCount(int[][] grid, int r, int c, boolean[][] visited) {
        // 如果当前方格已经访问过,则返回0
        if (visited[r][c]) {
            return 0;
        }
        // 标记当前方格为已访问
        visited[r][c] = true;
        // 计算可到达的方格数
        int count = 1;
        // 尝试向上移动
        if (r > 0 && canMove(grid, r, c, r-1, c)) {
            count += getCount(grid, r-1, c, visited);
        }
        // 尝试向下移动
        if (r < grid.length-1 && canMove(grid, r, c, r+1, c)) {
            count += getCount(grid, r+1, c, visited);
        }
        // 尝试向左移动
        if (c > 0 && canMove(grid, r, c, r, c-1)) {
            count += getCount(grid, r, c-1, visited);
        }
        // 尝试向右移动
        if (c < grid[0].length-1 && canMove(grid, r, c, r, c+1)) {
            count += getCount(grid, r, c+1, visited);
        }
        return count;
    }

    //移动判断
    public static boolean canMove(int[][] grid, int r1, int c1, int r2, int c2) {
        // 判断两个方格是否相邻
        if (Math.abs(r1 - r2) + Math.abs(c1 - c2) != 1) {
            return false;
        }
        // 判断两个方格的最大公约数是否大于1
        if (gcd(grid[r1][c1], grid[r2][c2]) > 1) {
            return true;
        }
        return false;
    }

    //欧几里得算法
    public static int gcd(int a, int b) {
        if (b == 0) {
            return a;
        }
        return gcd(b, a % b);
    }
}

 解析:这道题的思想并不难,只需要确定好固定的滑动窗口,然后一次枚举就行。只是在求滑动窗口内的和的时候,要考虑先求还是后求,后求类似于在线,时间复杂度会高一点。而先求类似于离线,时间复杂度会好很多。

//在线
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();  //长度
        int k = sc.nextInt();  //窗口大小
        int[] arr = new int[n];
        for(int i=0; i<n; i++) arr[i]=sc.nextInt(); //读入
        //存储最大值
        int max=0;
        for (int i = 0; i < n - k; i++) {  //依次枚举
            int sum=0;
            for (int j = i; j < k + i; j++) {  //确定固定的滑动窗口
                sum+=arr[j];   //在线累加窗口中所有和
            }
            max=max > sum ? max : sum;  //三元运算符比大小
        }
        System.out.println(max);
    }
}
//离线
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();  //长度
        int k = sc.nextInt();  //窗口大小
        int[] arr = new int[n];
        for (int i = 0; i < n; i++) {
            arr[i]=sc.nextInt();  //读入
        }
        //初始化sum为0,先累加窗口内的和
        int sum = 0;
        for (int i = 0; i < k; i++) {
            sum += arr[i];
        }
        //初始化maxSum为sum
        int maxSum = sum;
        for (int i = k; i < n; i++) {
            //从第k+1个元素开始遍历数组a
            //每次将sum减去上一个连续k个元素的第一个元素,并加上当前连续k个元素的最后一个元素,更新sum
            sum = sum - arr[i - k] + arr[i];
            //maxSum用于存储连续k个元素的和的最大值
            maxSum = Math.max(maxSum, sum);
        }
        System.out.println(maxSum);
    }
}

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我叫二叉树

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值