2018年蓝桥杯第九届javaA组省赛题解

蓝桥杯第九届省赛题解

1.标题:分数

1/1 + 1/2 + 1/4 + 1/8 + 1/16 + …
每项是前一项的一半,如果一共有20项,
求这个和是多少,结果用分数表示出来。
类似:
3/2
当然,这只是加了前2项而已。分子分母要求互质。

注意:
需要提交的是已经约分过的分数,中间任何位置不能含有空格。
请不要填写任何多余的文字或符号。

思路

手动计算:

等比数列,再约分

编码:

  1. 求和
  2. 约分:辗转相除法求最大公约数

答案:1048575/524288

static int GCD(int x,int y){
    if(y==0){
        return x;
    }
    return GCD(y,x%y);//是x%y,不是x/y
}
    public static void main(String[] args) {

        int bot=1;
        int top=1;
        for (int i = 1; i <20 ; i++) {
            top=2*top+1;
            bot=bot*2;
        }
        System.out.println(top+" "+bot);

        int gcd=top>bot?GCD(top,bot):GCD(bot,top);//没有if
        System.out.println(gcd);
        System.out.println(top/gcd+"/"+bot/gcd);

    }

2.标题:星期一

整个20世纪(1901年1月1日至2000年12月31日之间),一共有多少个星期一?
(不要告诉我你不知道今天是星期几)

注意:需要提交的只是一个整数,不要填写任何多余的内容或说明文字。

思路:

翻电脑日历得2000年12月31日是周日,按照周日,六,五,四,三,二,一的顺序往前推,共有36525/7=5217 个循环,余数是6.

答案:5217

    public static void main(String[] args){
        int day_sum=0;
        for (int i = 1901; i <=2000 ; i++) {
            if((i%400==0)||(i%4==0&&i%100!=0)){
                //leapYear
                day_sum+=366;
            }
            else{
                day_sum+=365;
            }

        }
        System.out.println(day_sum/7);
    }

3.标题:复数幂

设i为虚数单位。对于任意正整数n,(2+3i)^n 的实部和虚部都是整数。
求 (2+3i)^123456 等于多少? 即(2+3i)的123456次幂,这个数字很大,要求精确表示。

答案写成 “实部±虚部i” 的形式,实部和虚部都是整数(不能用科学计数法表示),中间任何地方都不加空格,实部为正时前面不加正号。(2+3i)^2 写成: -5+12i,
(2+3i)^5 的写成: 122-597i

注意:需要提交的是一个很庞大的复数,不要填写任何多余内容。

思路:

暴力计算,加上bigInteger,不需要用公式

不打印到控制台,文件输出

答案:

 public static void main(String[] args) throws FileNotFoundException {

        PrintStream ps=new PrintStream(new FileOutputStream("work.txt"));
        System.setOut(ps);  //文件输出
        BigInteger shi=new BigInteger("2");
        BigInteger xu=new BigInteger("3");
        for (int i = 0; i < 123456; i++) {
            BigInteger shi_t=shi.multiply(new BigInteger("2")).subtract(xu.multiply(new BigInteger("3")));
           BigInteger  xu_t=shi.multiply(new BigInteger("3")).add(xu.multiply(new BigInteger("2")));
           shi=shi_t;
          xu= xu_t;

        }
        if(xu.compareTo(new BigInteger("0"))==1){
            System.out.println(shi+"+"+xu+"i");
        }
        else{
            System.out.println(shi+"-"+xu.abs()+"i");
        }
    }

4.标题:方格计数

如图p1.png所示,在二维平面上有无数个1x1的小方格。

我们以某个小方格的一个顶点为圆心画一个半径为 50000 的圆。
你能计算出这个圆里有多少个完整的小方格吗?

注意:需要提交的是一个整数,不要填写任何多余内容。

思路:

遍历第一象限的方格,判断左上角到原点的距离是否为5000即可

答案:1107448696

public static void main(String[] args) {
        int ans=0;
        int r=50000;
        for (int i = 1; i <r ; i++) {
            for (int j = 1; j <r; j++) {
                if((i*i+j*j)<=r*r){
                    ans++;
                }
            }
        }
        System.out.println(ans*4);

    }

5.标题:打印图形

如下的程序会在控制台绘制分形图(就是整体与局部自相似的图形)。

当n=1,2,3的时候,输出如下:
请仔细分析程序,并填写划线部分缺少的代码。

n=1时:
o
ooo
o

n=2时:
o
ooo
o
o o o
ooooooooo
o o o
o
ooo
o

n=3时:
o
ooo
o
o o o
ooooooooo
o o o
o
ooo
o
o o o
ooo ooo ooo
o o o
o o o o o o o o o
ooooooooooooooooooooooooooo
o o o o o o o o o
o o o
ooo ooo ooo
o o o
o
ooo
o
o o o
ooooooooo
o o o
o
ooo
o

源程序:

public class Main
{
	static void show(byte[][] buf){
		for(int i=0; i<buf.length; i++){
			for(int j=0; j<buf[i].length; j++){
				System.out.print(buf[i][j]==0? ' ' : 'o');
			}
			System.out.println();
		}
	}
	
static void draw(byte[][] buf, int x, int y, int size){
	if(size==1){
		buf[y][x] = 1;
		return;
	}
	
	int n = ________________________ ;  // 填空
	draw(buf, x, y, n);
	draw(buf, x-n, y ,n);
	draw(buf, x+n, y ,n);
	draw(buf, x, y-n ,n);
	draw(buf, x, y+n ,n);
}

public static void main(String[] args){
	final int N = 3;
	int t = 1;
	for(int i=0; i<N; i++) t *= 3;
	
	byte[][] buf = new byte[t][t];
	draw(buf, t/2, t/2, t);
	show(buf);
}
}

注意:只提交划线部分缺少的代码,不要抄写任何已经存在的代码或符号。

思路:

观察可以发现n与size有关,其次图形是左右对称,想到3

答案:

size/3

6.标题:航班时间*

【问题背景】
小h前往美国参加了蓝桥杯国际赛。小h的女朋友发现小h上午十点出发,上午十二点到达美国,于是感叹到“现在飞机飞得真快,两小时就能到美国了”。

小h对超音速飞行感到十分恐惧。仔细观察后发现飞机的起降时间都是当地时间。由于北京和美国东部有12小时时差,故飞机总共需要14小时的飞行时间。

不久后小h的女朋友去中东交换。小h并不知道中东与北京的时差。但是小h得到了女朋友来回航班的起降时间。小h想知道女朋友的航班飞行时间是多少。

【问题描述】
对于一个可能跨时区的航班,给定来回程的起降时间。假设飞机来回飞行时间相同,求飞机的飞行时间。

【输入格式】
从标准输入读入数据。

一个输入包含多组数据。

输入第一行为一个正整数T,表示输入数据组数。

每组数据包含两行,第一行为去程的 起降 时间,第二行为回程的 起降 时间。

起降时间的格式如下

h1:m1:s1 h2:m2:s2

h1:m1:s1 h3:m3:s3 (+1)

h1:m1:s1 h4:m4:s4 (+2)
表示该航班在当地时间h1时m1分s1秒起飞,

第一种格式表示在当地时间 当日 h2时m2分s2秒降落

第二种格式表示在当地时间 次日 h3时m3分s3秒降落。

第三种格式表示在当地时间 第三天 h4时m4分s4秒降落。

对于此题目中的所有以 h : m 形式给出的时间, 保证 ( 0<=h<=23, 0<=m,s<=59 ).

【输出格式】
输出到标准输出。

对于每一组数据输出一行一个时间hh:mm:ss,表示飞行时间为hh小时mm分ss秒。

注意,当时间为一位数时,要补齐前导零。如三小时四分五秒应写为03:04:05。

【样例输入】
3
17:48:19 21:57:24
11:05:18 15:14:23
17:21:07 00:31:46 (+1)
23:02:41 16:13:20 (+1)
10:19:19 20:41:24
22:19:04 16:41:09 (+1)

【样例输出】
04:09:05
12:10:39
14:22:05

【限制与约定】
保证输入时间合法,飞行时间不超过24小时。

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
不要使用package语句。不要使用jdk1.7及以上版本的特性。
主类的名字必须是:Main,否则按无效代码处理。

思路:

  1. 字符串处理,将时间信息提取出来

  2. 航班时间=(第一组数据时间差+第二组数据时间差)/2,两地时差被约掉了

  3. 往:北京时间+飞行时间+时差=中东时间
    返:中东时间+飞行时间-时差=北京时间
    

答案:

  public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int sum = 0;
        sum = in.nextInt();
        int[] time = new int[2 * sum];
        for (int i = 0; i <= 2 * sum; i++) {
            if (i == 0) {
                String a = in.nextLine();
            } else {
                String first = in.nextLine();

                String[] one = first.split("\\s\\(\\+|:|\\)| ");//正则表达式
              	
                time[i - 1] = ((Integer.valueOf(one[3]) * 3600
                        + Integer.valueOf(one[4]) * 60 + Integer
                        .valueOf(one[5])) - (Integer.valueOf(one[0]) * 3600
                        + Integer.valueOf(one[1]) * 60 + Integer
                        .valueOf(one[2])));
                if (one.length > 6) {
                    time[i - 1] += Integer.valueOf(one[6]) * 24 * 3600;
                }

            }
        }
        int[] res = new int[sum];
        for (int i = 0; i < res.length; i++) {
            int aa[] = new int[3];
            res[i] = (time[2 * i + 1] + time[2 * i]) / 2;
          //时
            aa[0] = res[i] / 3600;
          //分
            aa[1] = (res[i] - aa[0] * 3600) / 60;
          //秒
            aa[2] = res[i] - aa[0] * 3600 - aa[1] * 60;
          
            String str1 = String.format("%02d", aa[0]);
            String str2 = String.format("%02d", aa[1]);
            String str3 = String.format("%02d", aa[2]);
            System.out.printf("%2s:%2s:%2s\n", str1, str2, str3);
        }
    }

7.标题:三体攻击

【题目描述】
三体人将对地球发起攻击。为了抵御攻击,地球人派出了 A × B × C 艘战舰,在太空中排成一个 A 层 B 行 C 列的立方体。其中,第 i 层第 j 行第 k 列的战舰(记为战舰 (i, j, k))的生命值为 d(i, j, k)。

三体人将会对地球发起 m 轮“立方体攻击”,每次攻击会对一个小立方体中的所有战舰都造成相同的伤害。具体地,第 t 轮攻击用 7 个参数 lat, rat, lbt, rbt, lct, rct, ht 描述;
所有满足 i ∈ [lat, rat],j ∈ [lbt, rbt],k ∈ [lct, rct] 的战舰 (i, j, k) 会受到 ht 的伤害。如果一个战舰累计受到的总伤害超过其防御力,那么这个战舰会爆炸。

地球指挥官希望你能告诉他,第一艘爆炸的战舰是在哪一轮攻击后爆炸的。

【输入格式】
从标准输入读入数据。
第一行包括 4 个正整数 A, B, C, m;
第二行包含 A × B × C 个整数,其中第 ((i − 1)×B + (j − 1)) × C + (k − 1)+1 个数为 d(i, j, k);
第 3 到第 m + 2 行中,第 (t − 2) 行包含 7 个正整数 lat, rat, lbt, rbt, lct, rct, ht。

【输出格式】
输出到标准输出。
输出第一个爆炸的战舰是在哪一轮攻击后爆炸的。保证一定存在这样的战舰。

【样例输入】
2 2 2 3
1 1 1 1 1 1 1 1
1 2 1 2 1 1 1
1 1 1 2 1 2 1
1 1 1 1 1 1 2

【样例输出】
2

【样例解释】
在第 2 轮攻击后,战舰 (1,1,1) 总共受到了 2 点伤害,超出其防御力导致爆炸。

【数据约定】
对于 10% 的数据,B = C = 1;
对于 20% 的数据,C = 1;
对于 40% 的数据,A × B × C, m ≤ 10, 000;
对于 70% 的数据,A, B, C ≤ 200;
对于所有数据,A × B × C ≤ 10^6, m ≤ 10^6, 0 ≤ d(i, j, k), ht ≤ 10^9。

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 3000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
不要使用package语句。不要使用jdk1.7及以上版本的特性。
主类的名字必须是:Main,否则按无效代码处理。

思路:

直接模拟

答案:

 public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        int A = s.nextInt();
        int B = s.nextInt();
        int C = s.nextInt();
        int m = s.nextInt();
        int[][][] cube = new int[A][B][C];
        for (int i = 0; i < A; i++) {
            for (int j = 0; j < B; j++) {
                for (int k = 0; k< C; k++) {
                    cube[i][j][k] = s.nextInt();
                }

            }

        }
        for (int i = 0; i < m; i++) {
            int lat=s.nextInt();
            int rat=s.nextInt();
            int lbt=s.nextInt();
            int rbt=s.nextInt();
            int lct=s.nextInt();
            int rct=s.nextInt();
            int ht=s.nextInt();
            for (int j = lat-1; j <=rat-1 ; j++) {
                for (int k = lbt-1; k <=rbt-1; k++) {
                    for (int l = lct-1; l <= rct-1; l++) {
                        cube[j][k][l]-=ht;
                        if(cube[j][k][l]<0){
                            System.out.println(i+1);
                            return;
                        }

                    }

                }

            }


        }
    }

8.标题:全球变暖*

你有一张某海域NxN像素的照片,".“表示海洋、”#"表示陆地,如下所示:


.##…
.##…
…##.
…####.
…###.

其中"上下左右"四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有2座岛屿。

由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。

例如上图中的海域未来会变成如下样子:





…#…

请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。

【输入格式】
第一行包含一个整数N。 (1 <= N <= 1000)
以下N行N列代表一张海域照片。

照片保证第1行、第1列、第N行、第N列的像素都是海洋。

【输出格式】 一个整数表示答案。

【输入样例】
7

.##…
.##…
…##.
…####.
…###.

【输出样例】
1

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
不要使用package语句。不要使用jdk1.7及以上版本的特性。
主类的名字必须是:Main,否则按无效代码处理。

思路:

  1. 一共有多少座岛屿:dfs搜索岛屿
  2. 有多少被淹没:在搜索过程中把使用数组把每座岛屿含有的不会被淹没的点数记录下来,当点数为0则会被淹没

答案:

static char[][] matrix;
    static boolean[][] vis;
    static int[] ans = new int[10000];
    //地图边长
    static int N;

  
    public static void dfs(int x, int y, int num) {
        if(x<0||x>=N||y<0||y>=N){
            return;
        }
        if (matrix[x][y] == '.') {
            return;
        }
        if (vis[x][y]) {
            return;
        }
        if (matrix[x + 1][y] != '.' && matrix[x - 1][y] != '.' && matrix[x][y + 1] != '.' && matrix[x][y - 1] != '.') {
            ans[num]++;
        }
        //设置为已经访问
        vis[x][y] = true;
        //四个方向搜索
        dfs(x + 1, y, num);
        dfs(x - 1, y, num);
        dfs(x, y + 1, num);
        dfs(x, y - 1, num);
    }

    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        N = s.nextInt();
        matrix = new char[N][N];
        vis = new boolean[N][N];
        //读取空格
        s.nextLine();
        //地图储存
        for (int i = 0; i < N; i++) {
            String line = s.nextLine();
            matrix[i] = line.toCharArray();
        }
        //岛屿数
        int num = 0;
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                if (matrix[i][j] == '#' && !vis[i][j]) {
                    dfs(i, j, num);
                    num++;

                }

            }

        }
        int res=0;
        for (int i = 0; i <num ; i++) {
            if(ans[i]==0){
                res++;
            }

        }
        System.out.println(res);
    }

9.标题:倍数问题

【题目描述】
众所周知,小葱同学擅长计算,尤其擅长计算一个数是否是另外一个数的倍数。但小葱只擅长两个数的情况,当有很多个数之后就会比较苦恼。现在小葱给了你 n 个数,希望你从这 n 个数中找到三个数,使得这三个数的和是 K 的倍数,且这个和最大。数据保证一定有解。

【输入格式】
从标准输入读入数据。
第一行包括 2 个正整数 n, K。
第二行 n 个正整数,代表给定的 n 个数。

【输出格式】
输出到标准输出。
输出一行一个整数代表所求的和。

【样例输入】
4 3
1 2 3 4

【样例输出】
9

【样例解释】
选择2、3、4。

【数据约定】
对于 30% 的数据,n <= 100。
对于 60% 的数据,n <= 1000。
对于另外 20% 的数据,K <= 10。
对于 100% 的数据,1 <= n <= 10^5, 1 <= K <= 10^3,给定的 n 个数均不超过 10^8。

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
不要使用package语句。不要使用jdk1.7及以上版本的特性。
主类的名字必须是:Main,否则按无效代码处理。

思路:

  1. 排序
  2. 从大往小搜索,是k的倍数就结束

答案:

 static ArrayList<Integer> nums = new ArrayList<Integer>();
    static boolean[] vis;
    static int[] res = new int[3];
    static int n;
    static int k;
    static int flag=0;

    public static void dfs(int cur) {
        if (cur == 3) {
            int sum = 0;
            for (int i = 0; i < 3; i++) {
                sum += res[i];
            }
            if (sum % k == 0) {
                System.out.println(sum);
                flag=1;
                return;
            }
            return;
        }
        for (int i = n - 1; i >= 0; i--) {
            if (res[cur] == Integer.MAX_VALUE && !vis[i]&&flag==0) {
                res[cur] = nums.get(i);
                vis[i] = true;

                dfs(cur + 1);
                res[cur] = Integer.MAX_VALUE;
                vis[i] = false;

            }

        }

    }

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

        n = s.nextInt();
        k = s.nextInt();

        vis = new boolean[n];
        for (int i = 0; i < 3; i++) {
            res[i] = Integer.MAX_VALUE;

        }
        for (int i = 0; i < n; i++) {
            int num = s.nextInt();
            nums.add(num);

        }
        Collections.sort(nums);

        dfs(0);

    }

10.标题:付账问题

【题目描述】
几个人一起出去吃饭是常有的事。但在结帐的时候,常常会出现一些争执。

现在有 n 个人出去吃饭,他们总共消费了 S 元。其中第 i 个人带了 ai 元。幸运的是,所有人带的钱的总数是足够付账的,但现在问题来了:每个人分别要出多少钱呢?

为了公平起见,我们希望在总付钱量恰好为 S 的前提下,最后每个人付的钱的标准差最小。这里我们约定,每个人支付的钱数可以是任意非负实数,即可以不是1分钱的整数倍。你需要输出最小的标准差是多少。

标准差的介绍:标准差是多个数与它们平均数差值的平方平均数,一般用于刻画这些数之间的“偏差有多大”。形式化地说,设第 i 个人付的钱为 bi 元,那么标准差为 : [参见p1.png]

【输入格式】
从标准输入读入数据。
第一行包含两个整数 n、S;
第二行包含 n 个非负整数 a1, …, an。

【输出格式】
输出到标准输出。
输出最小的标准差,四舍五入保留 4 位小数。
保证正确答案在加上或减去 10^−9 后不会导致四舍五入的结果发生变化。

【样例输入】
5 2333
666 666 666 666 666

【样例输出】
0.0000

【样例解释】
每个人都出 2333/5 元,标准差为 0。

再比如:
【样例输入】
10 30
2 1 4 7 4 8 3 6 4 7

【样例输出】
0.7928

【数据约定】
对于 10% 的数据,所有 ai 相等;
对于 30% 的数据,所有非 0 的 ai 相等;
对于 60% 的数据,n ≤ 1000;
对于 80% 的数据,n ≤ 10^5;
对于所有数据,n ≤ 5 × 10^5, 0 ≤ ai ≤ 10^9。

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
不要使用package语句。不要使用jdk1.7及以上版本的特性。
主类的名字必须是:Main,否则按无效代码处理。

思路:

  1. 难点在于不是整数,不是用搜索,而是贪心算法
  2. 贪心
    1. 每人的钱从小到大排序
    2. 每个人付的钱都经可能得接近平均值,钱不够则重新计算平均值,直到所有钱付完
  3. 计算标准差

答案:

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner in = new Scanner(System.in);
        int n;
        double S;
        n = in.nextInt();
        S = in.nextDouble();//当前需要缴纳的总费用
        int a[] = new int[n];
        double avg = (double)S/n;
        double original_avg = avg;
        double tmp = 0;//存(bi-avg)*(bi-avg)
        int left_person = n;//当前还剩多少人未付钱
        for(int i=0;i<n;i++)
        {
            a[i] = in.nextInt();
        }
        //先对每个人带的钱从小到大排序

        Arrays.sort(a);
        for (int i = 0; i <n ; i++) {
            System.out.println(a[i]);
        }

        //贪心算法,如果当前这个人付不起avg,他的钱全部交出去,更新avg
        for(int i=0;i<n;i++)//第i个人
        {//付不起,则将自己的a[i]全部上交
            if(a[i]<avg)
            {
                tmp += (a[i]-original_avg)*(a[i]-original_avg);
                S -= a[i];
                left_person--;
                avg = (double)S/left_person;
            }
            else
            {
                tmp += (n-i)*(avg-original_avg)*(avg-original_avg);//剩下的人都能交得起
                break;
            }
        }
        System.out.printf("%.4f",Math.sqrt(tmp/n));
    }

你可能感兴趣的:(二战蓝桥)