【2013年蓝桥杯Java-B组省赛题解】


题目主要考察对java特殊类class的掌握(Calender、BigDecimal),考察按照给定题目意思,模拟题目的能力,这里的模拟可能需要排序、搜索的帮助。未涉及DP。

一、世纪末的星期(Calender类)

标题: 世纪末的星期


    曾有邪教称1999年12月31日是世界末日。当然该谣言已经不攻自破。

    还有人称今后的某个世纪末的12月31日,如果是星期一则会....

    有趣的是,任何一个世纪末的年份的12月31日都不可能是星期一!! 

    于是,“谣言制造商”又修改为星期日......

    1999年的12月31日是星期五,请问:未来哪一个离我们最近的一个世纪末年(即xx99年)的12月31日正好是星期天(即星期日)?

    请回答该年份(只写这个4位整数,不要写12月31等多余信息)

直接用Calender类实现

import java.util.Calendar;

public class Main {
    public static void main(String[] args) {
        for (int i = 1999; i <= 9999; i = i + 100) {
            // 注意日历的声明方式
            Calendar calendar = Calendar.getInstance();
            // 注意日历中,月份是从0开始
            calendar.set(i, 12 - 1, 31);
            // 获取这一天是星期几注意星期日从”1“开始
            if (calendar.get(Calendar.DAY_OF_WEEK) == 1) {
                System.out.println(i);
                break;
            }
        }
    }
}

答案:2299

二、马虎的算式(暴力循环)

标题: 马虎的算式


    小明是个急性子,上小学的时候经常把老师写在黑板上的题目抄错了。

    有一次,老师出的题目是:36 x 495 = ?

    他却给抄成了:396 x 45 = ?

    但结果却很戏剧性,他的答案竟然是对的!!

    因为 36 * 495 = 396 * 45 = 17820

    类似这样的巧合情况可能还有很多,比如:27 * 594 = 297 * 54

    假设 a b c d e 代表1~9不同的5个数字(注意是各不相同的数字,且不含0)

    能满足形如: ab * cde = adb * ce 这样的算式一共有多少种呢?


请你利用计算机的优势寻找所有的可能,并回答不同算式的种类数。

满足乘法交换律的算式计为不同的种类,所以答案肯定是个偶数。


答案直接通过浏览器提交。
注意:只提交一个表示最终统计种类数的数字,不要提交解答过程或其它多余的内容。

直接暴力求解即可,五层for循环,每层遍历一位数字。一定要注意题目中说的满足乘法交换律的算式计为不同的种类,所以答案肯定是个偶数。

public class Main {
    public static void main(String[] args) {
        int ans = 0;
        for (int i = 1; i <= 9; i++) {
            for (int j = 1; j <= 9; j++) {
                if (j == i) continue;
                for (int k = 1; k <= 9; k++) {
                    if (i == k || j == k) continue;
                    for (int l = 1; l <= 9; l++) {
                        if (i == l || j == l || k == l) continue;
                        for (int m = 1; m <= 9; m++) {
                            if (i == m || j == m || k == m || l == m) continue;
                            int a1 = i * 10 + j;
                            int a2 = k * 100 + l * 10 + m;
                            int b1 = i * 100 + l * 10 + j;
                            int b2 = k * 10 + m;
                            if (a1 * a2 == b1 * b2) {
                                System.out.println(a1 + "*" + a2 + "=" + b1 + "*" + b2);
                                ans++;
                                continue;
                            }
                        }
                    }
                }
            }
        }
        System.out.println(ans);
    }
}

答案:142

三、振兴中华(DFS搜索)

标题: 振兴中华

    小明参加了学校的趣味运动会,其中的一个项目是:跳格子。

    地上画着一些格子,每个格子里写一个字,如下所示:(也可参见p1.jpg)

从我做起振
我做起振兴
做起振兴中
起振兴中华


    比赛时,先站在左上角的写着“从”字的格子里,可以横向或纵向跳到相邻的格子里,但不能跳到对角的格子或其它位置。一直要跳到“华”字结束。


    要求跳过的路线刚好构成“从我做起振兴中华”这句话。

    请你帮助小明算一算他一共有多少种可能的跳跃路线呢?

答案是一个整数,请通过浏览器直接提交该数字。
注意:不要提交解答过程,或其它辅助说明类的内容。

把“从我做起振兴中华”,依次标号为1-8,起点位于左上角,每次只能右移或者下移一格,满足题目条件:到达右下角 + (总和=(1+8) * 8 / 2 = 36)。

public class Main {
    static int[] x = {0, 1};
    static int[] y = {1, 0};
    static int[][] vis = new int[8][8];
    static int ans = 0;
    public static void main(String[] args) {
        // 从:1 我:2 做:3 起:4 振:5 兴:6 中:7 华:8
        int[][] map = new int[][] {
                {1, 2, 3, 4, 5},
                {2, 3, 4, 5, 6},
                {3, 4, 5, 6, 7},
                {4, 5, 6, 7, 8}
        };
        vis[0][0] = 1;
        dfs(map, 0, 0, 1);
        System.out.println(ans);
    }
    static void dfs(int[][] map, int i, int j, int cnt) {
        // (1 + 8) * 8 / 2 = 36
        if (cnt == 36 && i == 3 && j == 4) {
            ans++;
            return;
        }
        for (int k = 0; k < 2; k++) {
            int tempx = i + x[k];
            int tempy = j + y[k];
            if (tempx >= 4 || tempy >= 5 || vis[tempx][tempy] == 1) {
                continue;
            }
            vis[tempx][tempy] = 1;
            dfs(map, tempx, tempy, cnt + map[tempx][tempy]);
            // 找路线种类,一定要记得回溯
            vis[tempx][tempy] = 0;
        }
    }
}

答案:35

四、黄金连分数(BigDecimal类)

标题: 黄金连分数


    黄金分割数0.61803... 是个无理数,这个常数十分重要,在许多工程问题中会出现。有时需要把这个数字求得很精确。

    对于某些精密工程,常数的精度很重要。也许你听说过哈勃太空望远镜,它首次升空后就发现了一处人工加工错误,对那样一个庞然大物,其实只是镜面加工时有比头发丝还细许多倍的一处错误而已,却使它成了“近视眼”!!


    言归正传,我们如何求得黄金分割数的尽可能精确的值呢?有许多方法。

    比较简单的一种是用连分数:

                  1
    黄金数 = ---------------------
                        1
             1 + -----------------
                          1
                 1 + -------------
                            1
                     1 + ---------
                          1 + ...

                           

    这个连分数计算的“层数”越多,它的值越接近黄金分割数。

    请你利用这一特性,求出黄金分割数的足够精确值,要求四舍五入到小数点后100位。

    小数点后3位的值为:0.618
    小数点后4位的值为:0.6180
    小数点后5位的值为:0.61803
    小数点后7位的值为:0.6180340
   (注意尾部的0,不能忽略)

你的任务是:写出精确到小数点后100位精度的黄金分割值。

注意:尾数的四舍五入! 尾数是0也要保留!

显然答案是一个小数,其小数点后有100位数字,请通过浏览器直接提交该数字。
注意:不要提交解答过程,或其它辅助说明类的内容。

在这里插入图片描述

100位小数,对于java来说,可以直接使用BigDecimal类来实现。注意使用大小数divide除法时,一定要指定小数位数,和小数保留方式,否则会报错:Non-terminating decimal expansion; no exact representable decimal result.

import java.math.BigDecimal;
import java.math.RoundingMode;

public class Main {
    public static void main(String[] args) {
        BigDecimal bd = new BigDecimal(1);
        BigDecimal tmp = new BigDecimal(1);
        for (int i = 0; i < 10000; i++) {
            // 指定保留小数位数101位,保留方式四舍五入
            BigDecimal ans = bd.divide(bd.add(tmp), 101, RoundingMode.HALF_UP);
            tmp = ans;
            System.out.println(ans);
            System.out.println(ans.scale());
        }
    }

算到第101位是9,第100位是4,四舍五入后为5。
答案:0.6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911375

五、六为填空题跳过

七、错误票据(注意输入、部分排序)(排序)

在这里插入图片描述
在这里插入图片描述
注意我们不知道输入数字的多少,只知道输入的行数,所以可以选择以一行字符串的形式读入数据,再把字符串split形成String[]数组,再把String转成int即可。

注意next是遇到空格就停止,nextLine是遇到回车停止。

把重新处理好的数组进行排序,排序的时候也要注意,我们只需要对第0 - index - 1的数组元素排序,所以要选择部分数组元素进行排序。判断前后两个数组元素是否相等、连续,就可以得到两个答案。

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

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        // 因为不知道要读入多少数字,所以直接读入字符串next遇到空格停止
        // nextLine遇到回车停止
        String n = scan.nextLine();
        int nn = Integer.parseInt(n);
        int[] nums = new int[101];
        String[] str = new String[nn];
        int index = 0;
        for (int i = 0; i < nn; i++) {
            str[i] = scan.nextLine();
            String[] tmp = str[i].split(" ");
            for (int j = 0; j < tmp.length; j++) {
                nums[index++] = Integer.parseInt(tmp[j]);
            }
        }
        // 部分排序
        // 只对0 - index - 1的位置排序
        Arrays.sort(nums, 0, index);
        int ans1 = 0;
        int ans2 = 0;
        for (int i = 1; i < index; i++) {
            if (nums[i] == nums[i - 1]) {
                ans2 = nums[i];
                continue;
            }
            if (nums[i] != nums[i - 1] + 1) {
                ans1 = nums[i - 1] + 1;
                continue;
            }
        }
        System.out.printf("%d %d", ans1, ans2);
    }
}

八、幸运数(模拟)

在这里插入图片描述
按照题目意思模拟,对已经剔除的数用vis数组记录,每次记录剩下的数的下标,能整除就标记为1。最后剩下vis=0的数就是幸运数。

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int m = scan.nextInt();
        int n = scan.nextInt();
        // 标记哪些是幸运数
        int[] vis = new int[n + 1];
        // tmp用于记录每次的幸运数
        int tmp = 2;
        boolean flag = true;
        while (flag) {
            // 记录当前数字的下标
            int index = 0;
            for (int i = 1; i <= n; i++) {
                if (vis[i] == 0) {
                    index++;
                    if (index % tmp == 0) {
                        vis[i] = 1;
                    }
                }
            }
            // 更新tmp,注意:数字1不考虑
            for (int i = tmp + 1; i <= n; i++) {
                if (vis[i] == 0) {
                    tmp = i;
                    break;
                }
                if (i == n) {
                    flag = false;
                }
            }
        }
        // 打印结果
        int ans = 0;
        for (int i = m + 1; i < n; i++) {
            if (vis[i] == 0) {
                ans++;
            }
        }
        System.out.println(ans);
    }
}

九、带分数(全排列、搜索)

在这里插入图片描述
先求1-9的全排列,然后对每种组合check,把除法转成乘法,如果满足题意结果++。

求全排列的方法可以参考之前的回溯专题一,需要注意在同一分支中,使用过的数字要用vis标记。

import java.util.*;

public class Main {
    static LinkedList<Integer> tmp = new LinkedList<>();
    static int ans = 0;
    static int[] vis = new int[10];
    static int n;
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        n = scan.nextInt();
        dfs();
        System.out.println(ans);
    }
    static void dfs() {
        if (tmp.size() == 9) {
            // n = a + b/c
            // n*c = a*c + b
            // i j k 三个循环依次遍历a b c三个数
            int a = 0;
            for (int i = 0; i < 9 - 2; i++) {
                a = a * 10 + tmp.get(i);
                if (a >= n) {
                    break;
                }
                int b = 0;
                for (int j = i + 1; j < 9 - 1; j++) {
                    b = b * 10 + tmp.get(j);
                    int c = 0;
                    for (int k = j + 1; k < 9; k++) {
                        c = c * 10 + tmp.get(k);
                        // 满足题目条件,并且是用完了所有的数
                        if (n * c == a * c + b && k == 8) {
                            ans++;
//                            System.out.println(tmp);
//                            System.out.println(a + " " + b + " " + c);
                            break;
                        }
                    }
                }
            }
            return;
        }
        if (tmp.size() > 9) {
            return;
        }
        for (int i = 1; i <= 9; i++) {
            if (vis[i] == 1) {
                continue;
            }
            vis[i] = 1;
            tmp.add(i);
            dfs(i);
            // 回溯
            tmp.removeLast();
            vis[i] = 0;
        }
    }
}

十、连号区间数(模拟)

在这里插入图片描述
在这里插入图片描述
首先,1,1 2,2 3,3 4,4…n,n都是,就不用再考虑,直接初始化答案为n。考虑3 2 4 1,对于区间[1,2],找到其中的最大值、最小值,max-min = 2 - 1,最大值和最小值的差值是否等于区间差值,等于的话就找到了新的连号区间。

这道题一开始想法是dp,但是发现状态转移方程推不出来就尝试直接模拟。

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        // 1,1 2,2 3,3 ... n,n都是
        int ans = n;
        int[] nums = new int[n];
        for (int i = 0; i < n; i++) {
            nums[i] = scan.nextInt();
        }
        for (int i = 0; i < n; i++) {
            int min = nums[i];
            int max = nums[i];
            // 一直记录最大最小值,不需要再去开第三个循环
            for (int j = i + 1; j < n; j++) {
                min = Math.min(min, nums[j]);
                max = Math.max(max, nums[j]);
                if (max - min == j - i) {
                    ans++;
                }
            }
        }
        System.out.println(ans);
    }
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

@u@

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

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

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

打赏作者

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

抵扣说明:

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

余额充值