2017年第八届蓝桥杯国赛试题及详解(Java本科B组)

1. 平方十位数

由0~9这10个数字不重复、不遗漏,可以组成很多10位数字。
这其中也有很多恰好是平方数(是某个数的平方)。

比如:1026753849,就是其中最小的一个平方数。

请你找出其中最大的一个平方数是多少?

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

解析:

签到题,暴力搜索

package A;

public class Main {
    static int[] arr = new int[15];
    static int[] vis = new int[15];
    static long max = 0;
    static void dfs(int n) {
        if (n == 10 && arr[0] != 0) {
            long num = 0;
            for (int i = 0; i < 10; i++) {
                num = num*10 + arr[i];
            }
            double a = Math.sqrt(num);
            int b = (int)a;
            if (a == b) {
                if (num > max) max = num;
                
            }
            return ;
        }
        
        for (int i = 0; i < 10; i++) {
            if (vis[i] == 0) {
                vis[i] = 1;
                arr[n] = i;
                dfs(n+1);
                vis[i] = 0;
            }
        }
    }
    public static void main(String[] args) {
        dfs(0);
        System.out.println(max);
    }
}

我的答案是:9814072356

2. 生命游戏

标题:生命游戏

康威生命游戏是英国数学家约翰·何顿·康威在1970年发明的细胞自动机。
这个游戏在一个无限大的2D网格上进行。

初始时,每个小方格中居住着一个活着或死了的细胞。
下一时刻每个细胞的状态都由它周围八个格子的细胞状态决定。

具体来说:

  1. 当前细胞为存活状态时,当周围低于2个(不包含2个)存活细胞时, 该细胞变成死亡状态。(模拟生命数量稀少)
  2. 当前细胞为存活状态时,当周围有2个或3个存活细胞时, 该细胞保持原样。
  3. 当前细胞为存活状态时,当周围有3个以上的存活细胞时,该细胞变成死亡状态。(模拟生命数量过多)
  4. 当前细胞为死亡状态时,当周围有3个存活细胞时,该细胞变成存活状态。 (模拟繁殖)

当前代所有细胞同时被以上规则处理后, 可以得到下一代细胞图。按规则继续处理这一代的细胞图,可以得到再下一代的细胞图,周而复始。

例如假设初始是:(X代表活细胞,.代表死细胞)

.....
.....
.XXX.
.....

下一代会变为:

.....
..X..
..X..
..X..
.....

康威生命游戏中会出现一些有趣的模式。例如稳定不变的模式:

....
.XX.
.XX.
....

还有会循环的模式:

......      ......       ......
.XX...      .XX...       .XX...
.XX...      .X....       .XX...
...XX.   -> ....X.  ->   ...XX.
...XX.      ...XX.       ...XX.
......      ......       ......

本题中我们要讨论的是一个非常特殊的模式,被称作"Gosper glider gun":

......................................
.........................X............
.......................X.X............
.............XX......XX............XX.
............X...X....XX............XX.
.XX........X.....X...XX...............
.XX........X...X.XX....X.X............
...........X.....X.......X............
............X...X.....................
.............XX.......................
......................................

假设以上初始状态是第0代,请问第1000000000(十亿)代一共有多少活着的细胞?

注意:我们假定细胞机在无限的2D网格上推演,并非只有题目中画出的那点空间。
当然,对于遥远的位置,其初始状态一概为死细胞。

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

解析:

这道题得暴力找规律,注意是无限的2D网格,所以把图放在中间一点模拟

规律是每隔30代细胞数量增殖5,
而且30代细胞变化是一个固定的值
{3, 4, 5, 3, -7, 7, -3, 13, -19, 6, 2, 4, 1, 1, -14, 2, 3, 6, 1, 0, 0, -5, 11, -17, 7, -3, 0, 3, -2, -7}

package B;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.StringTokenizer;

public class Main {
    static InputReader in = new InputReader(new BufferedInputStream(System.in));
    static PrintWriter out = new PrintWriter(System.out);
    static int[][] G = new int[305][305];
    static int[][] tmp = new int[305][305];
    static int pos = 30; // 定义一个偏移
    static int[] pmove = {0, 0, -1, 1, -1, 1, -1, 1};
    static int[] qmove = {1, -1, 0, 0, 1, 1, -1, -1};
    
    static int row = 11, col = 38;
    static int change() {
        for (int i = 0; i < 300; i++) {
            for (int j = 0; j < 300; j++) {
                judge(i, j);
            }
        }
        
        int sum = 0;
        for (int i = 0; i < 300; i++) {
            for (int j = 0; j < 300; j++) {
                G[i][j] = tmp[i][j];
                if (G[i][j] == 1) {
                    sum++;
                }
            }
        }
        return sum;
    }
    
    static void judge(int x, int y) {
        boolean flag = false;
        if (G[x][y] == 1) flag = true;
        
        int sum = 0; // 存活的细胞
        for (int i = 0; i < 8; i++) {
            int nx = x + pmove[i];
            int ny = y + qmove[i];
            if (nx >= 0 && ny >= 0 ) {
                if (G[nx][ny] == 1) {
                    sum++;
                }
            }
        }
        
        if (flag && sum < 2) {
            tmp[x][y] = 0;
        } else if (flag && (sum == 2 || sum == 3)) {
            tmp[x][y] = 1;
        } else if (flag && sum > 3) {
            tmp[x][y] = 0;
        } else if (!flag && sum == 3) {
            tmp[x][y] = 1;
        }
    }
    
    static void print() {
        for (int i = pos; i < row+pos; i++) {
            for (int j = pos; j < col+pos; j++) {
                if (tmp[i][j] == 0) 
                System.out.print('.');
                else System.out.print('X');
            }
            System.out.println();
        }
        System.out.println("-------------------");
        System.out.println();
    }
    
    // 模拟一下 找规律。
    public static void main(String[] args) {
        for (int i = pos; i < row+pos; i++) {
            String s = in.readLine();
            col = s.length();
            for (int j = 0; j < s.length(); j++) {
                if (s.charAt(j) == '.') {
                    G[i][j+pos] = 0;
                } else {
                    G[i][j+pos] = 1;
                }
                tmp[i][j] = G[i][j];
            }
        }
        
        System.out.println();
        int pre = change();
        System.out.println("第1代" + "存活的有:" + pre + "个");
        for (int i = 2; i <= 1000; i++) {
            // print();
            int sum = change();
            System.out.println("第" + i + "代" + "存活的有:" + sum + "个" + "与上一代差异了" + (sum-pre));
            pre = sum;
        }
        
        long[] add = {0, 3, 4, 5, 3, -7, 7, -3, 13, -19, 6, 2, 4, 1, 1, -14, 2, 3, 6, 1, 0, 0, -5, 11, -17, 7, -3, 0, 3, -2, -7};
        long num = 1000000000L;
        long res = 36 + (num / 30) * 5;
        long ans = 0;
        for (int i = 1; i <= num%30; i++) {
            ans += add[i];
        }        
        System.out.println(ans + res);
    }
    
    public static class InputReader {
        public static BufferedReader br;
        public static StringTokenizer tokenizer;
        
        public InputReader(InputStream stream) {
            br = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }
        
        public String next() {
            while(tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            return tokenizer.nextToken();
        }
        
        public String readLine() {
            String s = null;
            try {
                s = br.readLine();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return s;
        }
        
        public int nextInt() {
            return Integer.parseInt(next());
        }
        
        public Long nextLong() {
            return Long.parseLong(next());
        }
        
        public Double nextDouble() {
            return Double.parseDouble(next());
        }
    }

}

3. 树形显示

我的答案是:(last_child(pa) ? " " : "|") + space(4) + s

4. 小计算器

模拟程序型计算器,依次输入指令,可能包含的指令有

  1. 数字:‘NUM X’,X为一个只包含大写字母和数字的字符串,表示一个当前进制的数
  2. 运算指令:‘ADD’,‘SUB’,‘MUL’,‘DIV’,‘MOD’,分别表示加减乘,除法取商,除法取余
  3. 进制转换指令:‘CHANGE K’,将当前进制转换为K进制(2≤K≤36)
  4. 输出指令:‘EQUAL’,以当前进制输出结果
  5. 重置指令:‘CLEAR’,清除当前数字

指令按照以下规则给出:
数字,运算指令不会连续给出,进制转换指令,输出指令,重置指令有可能连续给出
运算指令后出现的第一个数字,表示参与运算的数字。且在该运算指令和该数字中间不会出现运算指令和输出指令
重置指令后出现的第一个数字,表示基础值。且在重置指令和第一个数字中间不会出现运算指令和输出指令
进制转换指令可能出现在任何地方

运算过程中中间变量均为非负整数,且小于2^63
以大写的'A'~'Z'表示10~35

[输入格式]
第1行:1个n,表示指令数量
第2…n+1行:每行给出一条指令。指令序列一定以’CLEAR’作为开始,并且满足指令规则

[输出格式]
依次给出每一次’EQUAL’得到的结果

[样例输入]
7
CLEAR
NUM 1024
CHANGE 2
ADD
NUM 100000
CHANGE 8
EQUAL

[样例输出]
2040

补充说明:

  1. n 值范围: 1<= n < 50000
  2. 初始默认的进制是十进制

资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms

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

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

解析:

题目本身不难,但要注意细心一些。

  1. 数据是小于2^63的,因此要用Long型存
  2. NUM X,这个X可能是数字也可能是大写字母
  3. 输出的时候,如果有字母,要输出大写字母

代码

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.StringTokenizer;

public class Main {
    static InputReader in = new InputReader(new BufferedInputStream(System.in));
    static PrintWriter out = new PrintWriter(System.out);
    
    public static void main(String[] args) {
        int n = in.nextInt();
        int jz = 10;
        boolean flag = false;
        Long sum = 0L;
        String ys = "";
        for (int i = 0; i < n; i++) {
            String s = in.next();
            if (s.equals("NUM")) {
                String num = in.next();
                // 将当前进制字母和大写数字,转换为十进制数字,进行运算
                if (flag) {
                    sum = Long.parseLong(num, jz);
                    flag = false;
                } else {
                    if (ys.equals("ADD")) {
                        sum += Long.parseLong(num, jz);
                    } else if (ys.equals("SUB")) {
                        sum -= Long.parseLong(num, jz);
                    } else if (ys.equals("MUL")) {
                        sum *= Long.parseLong(num, jz);
                    } else if (ys.equals("DIV")) {
                        sum /= Long.parseLong(num, jz);
                    } else if (ys.equals("MOD")) {
                        sum %= Long.parseLong(num, jz);
                    }
                }
            } else if (s.equals("CHANGE")) {
                jz = in.nextInt();
            } else if (s.equals("EQUAL")) {
                out.println(Long.toString(sum, jz).toUpperCase());
                out.flush();
            } else if (s.equals("CLEAR")) {
                flag = true;
            } else {
                ys = s;
            }
        }
        out.close();
    }
    
    public static class InputReader {
        public static BufferedReader br;
        public static StringTokenizer tokenizer;
        
        public InputReader(InputStream stream) {
            br = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }
        
        public String next() {
            while(tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            return tokenizer.nextToken();
        }
        
        public String readLine() {
            String s = null;
            try {
                s = br.readLine();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return s;
        }
        
        public int nextInt() {
            return Integer.parseInt(next());
        }
        
        public Long nextLong() {
            return Long.parseLong(next());
        }
        
        public Double nextDouble() {
            return Double.parseDouble(next());
        }
    }

}

5. 填字母游戏

标题:填字母游戏

小明经常玩 LOL 游戏上瘾,一次他想挑战K大师,不料K大师说:
“我们先来玩个空格填字母的游戏,要是你不能赢我,就再别玩LOL了”。

K大师在纸上画了一行n个格子,要小明和他交替往其中填入字母。

并且:

  1. 轮到某人填的时候,只能在某个空格中填入L或O
  2. 谁先让字母组成了“LOL”的字样,谁获胜。
  3. 如果所有格子都填满了,仍无法组成LOL,则平局。

小明试验了几次都输了,他很惭愧,希望你能用计算机帮他解开这个谜。

本题的输入格式为:
第一行,数字n(n<10),表示下面有n个初始局面。
接下来,n行,每行一个串,表示开始的局面。
比如:“******”, 表示有6个空格。
“L****”, 表示左边是一个字母L,它的右边是4个空格。

要求输出n个数字,表示对每个局面,如果小明先填,当K大师总是用最强着法的时候,小明的最好结果。
1 表示能赢
-1 表示必输
0 表示可以逼平

例如,
输入:
4
***
L**L
L**L***L
L*****L

则程序应该输出:
0
-1
1
1

资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms

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

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

解析:

暴力递归,只能拿20分

package E;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;

public class Main {    
    static int f(char[] x) {
        String s = new String(x);
        if (s.contains("LOL")) return -1;
        if (s.contains("*") == false) return 0;
        boolean ping = false;
        for (int i = 0; i < x.length; i++) {
            if (x[i] == '*') {
                try {
                    // 试填入L
                    x[i] = 'L'; 
                    switch(f(x)) {
                        case -1: return 1;
                        case 0: ping = true;
                    }
                    // 试填入O
                    x[i] = 'O';
                    switch(f(x)) {
                        case -1: return 1;
                        case 0: ping = true;
                    }
                } finally {
                    x[i] = '*'; // 回溯
                }
            }
        }
        if (ping) return 0;
        return -1;
    }
    
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in), 32768);
        PrintWriter out = new PrintWriter(System.out);
        int n = Integer.parseInt(br.readLine());
        for (int i = 0; i < n; i++) {
            String s = br.readLine();
            out.println(f(s.toCharArray()));
            out.flush();
        }
        out.close();
    }
}

6. 区间移位

待更新。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值