蓝桥杯历年真题题目及题解目录汇总(推荐)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2017年第八届蓝桥杯国赛试题及详解(Java本科B组)
- 结果填空 (满分17分)
- 结果填空 (满分45分)
- 代码填空 (满分23分)
- 程序设计(满分43分)
- 程序设计(满分71分)
- 程序设计(满分101分)
1.标题:平方十位数
由0~9这10个数字不重复、不遗漏,可以组成很多10位数字。
这其中也有很多恰好是平方数(是某个数的平方)。
比如:1026753849,就是其中最小的一个平方数。
请你找出其中最大的一个平方数是多少?
注意:你需要提交的是一个10位数字,不要填写任何多余内容。
---------------------
思路:一开始以为直接最大值开根号取整+1就结束,但是不能重复啊
代码:
package lq2017_gs; /* 1.标题:平方十位数 由0~9这10个数字不重复、不遗漏,可以组成很多10位数字。 这中也有很多恰好是平方数(是某个数的平方)。 比如:1026753849,就是其中最小的一个平方数。 请你找出其中最大的一个平方数是多少? 注意:你需要提交的是一个10位数字,不要填写任何多余内容。 */ public class t1 { public static void main(String[] args) { long MAX = (int) Math.sqrt(9876543210.0); // int 9876543210超过了范围 for(long i = MAX; i >= 1; i--) { int a[] = new int[10]; long x = i * i; int flag = 1; while(x != 0) { int y = (int) (x % 10); if(a[y] == 0) { a[y] = 1; } else { flag = 0; break; } x /= 10; } for(int j = 0; j < 10; j++) { if(a[j] == 0) { flag = 0; break; } } if(flag == 1) { System.out.println(i); System.out.println(i * i); break; } } } }
答案: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网格上推演,并非只有题目中画出的那点空间。
当然,对于遥远的位置,其初始状态一概为死细胞。
注意:需要提交的是一个整数,不要填写多余内容。
---------------------
思路: 开始受题目引导,以为后面的不会变化,存在某种循环,但是一直没找到,其实应该从数量循环来着手,
因为的位置可能会一直向某个方向偏移。分析数量时,直接观察后面每代的数量也不直观,要做差,得到相邻两
天的增长数量,可以将得到的差值,放入excel绘制折线图,来直观的找周期。
我找了前200代,第一列记录该代数量,第二列记录了比前一代增长的数量:
将差值绘制折线图:
可以直观的看到是周期分布的,结合表格可以确定周期为30代:
故可以发现,每30代增长5个细胞。
30内每代增长数量为:
所以最终的答案就是: 1000000000 / 30 * 5 + (1000000000 % 30 ) 12 = 166666713
代码:
package lq2017_gs; import java.util.Scanner; public class t2 { public static void main(String[] args) { Scanner cin = new Scanner(System.in); String st = "23"; char[][] map = new char[1000][1000]; for(int i = 0; i < 1000; i++) { for(int j = 0; j < 1000; j++) { map[i][j] = '.'; } } // System.out.println(map[0][0]); int p = 300; for(int i = p; i < p + 11; i++) { String s = cin.next(); System.out.println("sss---" + s + s.length()); for(int j = p; j < p + 38; j++) { map[i][j] = s.charAt(j - p); } } int dx[] = {-1, -1, -1, 0, 0, 1, 1, 1}; int dy[] = {-1, 0, 1, -1, 1, -1, 0, 1}; int t = 200; int all = 0; int ans1 = 36; int ans2 = 0; while(t-- != 0) { // System.out.println("------+++"); char[][] map2 = new char[1000][1000]; for(int i = 0; i < 1000; i++) { for(int j = 0; j < 1000; j++) { int f = 0; for(int k = 0; k < 8; k++) { int x = i + dx[k]; int y = j + dy[k]; if(x >= 0 && x < 1000 && y >= 0 && y < 1000) { if(map[x][y] == 'X') { f++; } } } if(map[i][j] == 'X') { if(f < 2) { map2[i][j] = '.'; } else if(f == 2 || f == 3) { map2[i][j] = 'X'; } else{ map2[i][j] = '.'; } } else { if(f == 3) { map2[i][j] = 'X'; } else { map2[i][j] = '.'; } } } } ans2 = 0; int flag = 1; for(int i = 0; i < 1000; i++) { for(int j = 0; j < 1000; j++) { if(map2[i][j] == 'X') { ans2++; } } } // System.out.println(ans2 - ans1); // 输出找规律 ans1 = ans2; map = map2; } // 通过分析得知响邻两天之间增长个数有规律,每个30天增长5个 int yuan = 36; // int now = 0; int zs = 36 / 30; int ys = 36 % 30; System.out.println(zs + ", " + ys); now = zs * 5 + yuan; // 还要加上余数增长的个数 System.out.println("now: " + (now + 12)); //166666713 } } /* * * ans = 9814072356 * * */
3.标题:树形显示
对于分类结构可以用树形来形象地表示。比如:文件系统就是典型的例子。
树中的结点具有父子关系。我们在显示的时候,把子项向右缩进(用空格,不是tab),并添加必要的连接线,以使其层次关系更醒目。
下面的代码就是为了这个目的的,请仔细阅读源码,并填写划线部分缺少的代码。
package lq2017_gs; import java.util.*; class MyTree { private Map<String, List<String>> map_ch = new HashMap<String, List<String>>(); private Map<String,String> map_pa = new HashMap<String,String>(); public void add(String parent, String child) { map_pa.put(child, parent); List<String> lst = map_ch.get(parent); if(lst==null){ lst = new ArrayList<String>(); map_ch.put(parent, lst); } lst.add(child); } public String get_parent(String me){ return map_pa.get(me); } public List<String> get_child(String me){ return map_ch.get(me); } private String space(int n) { String s = ""; for(int i=0; i<n; i++) s += ' '; return s; } private boolean last_child(String x){ String pa = map_pa.get(x); if(pa==null) return true; List<String> lst = map_ch.get(pa); return lst.get(lst.size()-1).equals(x); } public void show(String x){ String s = "+--" + x; String pa = x; while(true){ pa = map_pa.get(pa); if(pa==null) break; // s = _________ ; // 填空 } System.out.println(s); } public void dfs(String x){ show(x); List<String> lst = map_ch.get(x); if(lst==null) return; for(String it: lst){ dfs(it); } } } public class t3 { public static void main(String[] args) { MyTree tree = new MyTree(); tree.add("root", "dog"); tree.add("root", "cat"); tree.add("root", "duck"); tree.add("dog", "AAdog"); tree.add("dog", "BBdog"); tree.add("dog", "CCdog"); tree.add("AAdog", "AAdog01"); tree.add("AAdog", "AAdog02"); tree.add("cat", "XXcat"); tree.add("cat", "YYcat"); tree.add("XXcat","XXcat-oo"); tree.add("XXcat","XXcat-qq"); tree.add("XXcat-qq", "XXcat-qq-hahah"); tree.add("duck", "TTduck"); tree.add("TTduck", "TTduck-001"); tree.add("TTduck", "TTduck-002"); tree.add("TTduck", "TTduck-003"); tree.add("YYcat","YYcat.hello"); tree.add("YYcat","YYcat.yes"); tree.add("YYcat","YYcat.me"); tree.dfs("root"); } }
对于题目中的测试数据,输出结果:
+--root
+--dog
| +--AAdog
| | +--AAdog01
| | +--AAdog02
| +--BBdog
| +--CCdog
+--cat
| +--XXcat
| | +--XXcat-oo
| | +--XXcat-qq
| | +--XXcat-qq-hahah
| +--YYcat
| +--YYcat.hello
| +--YYcat.yes
| +--YYcat.me
+--duck
+--TTduck
+--TTduck-001
+--TTduck-002
+--TTduck-003
如有平字体对齐问题,可以参见图【p1.png】
注意,只填写划线部分缺少的代码,不要抄写已有的代码或符号。
---------------------
个人答案:
s = last_child(pa) == true ? space(5) + s : "|" + 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,否则按无效代码处理。
---------------------
思路: 充分利用java的BigInteger。
构造方法摘要 | |
---|---|
BigInteger(byte[] val)
将包含 BigInteger 的二进制补码表示形式的 byte 数组转换为 BigInteger。 |
|
BigInteger(int signum,
byte[] magnitude) 将 BigInteger 的符号-数量表示形式转换为 BigInteger。 |
|
BigInteger(int bitLength,
int certainty, Random rnd)
构造一个随机生成的正 BigInteger,它可能是一个具有指定 bitLength 的素数。 |
|
BigInteger(int numBits,
Random rnd)
构造一个随机生成的 BigInteger,它是在 0 到 (2numBits - 1)(包括)范围内均匀分布的值。 |
|
BigInteger(String val)
将 BigInteger 的十进制字符串表示形式转换为 BigInteger。 |
|
BigInteger(String val,
int radix) 将指定基数的 BigInteger 的字符串表示形式转换为 BigInteger。 |
方法摘要 | |
---|---|
BigInteger |
abs()
返回其值是此 BigInteger 的绝对值的 BigInteger。 |
BigInteger |
add(BigInteger val)
返回其值为 (this + val) 的 BigInteger。 |
BigInteger |
and(BigInteger val)
返回其值为 (this & val) 的 BigInteger。 |
BigInteger |
andNot(BigInteger val)
返回其值为 (this & ~val) 的 BigInteger。 |
int |
bitCount()
返回此 BigInteger 的二进制补码表示形式中与符号不同的位的数量。 |
int |
bitLength()
返回此 BigInteger 的最小的二进制补码表示形式的位数,不包括 符号位。 |
BigInteger |
clearBit(int n)
返回其值与清除了指定位的此 BigInteger 等效的 BigInteger。 |
int |
compareTo(BigInteger val)
将此 BigInteger 与指定的 BigInteger 进行比较。 |
BigInteger |
divide(BigInteger val)
返回其值为 (this / val) 的 BigInteger。 |
BigInteger[] |
divideAndRemainder(BigInteger val)
返回包含 (this / val) 后跟 (this % val) 的两个 BigInteger 的数组。 |
double |
doubleValue()
将此 BigInteger 转换为 double 。 |
boolean |
equals(Object x)
比较此 BigInteger 与指定的 Object 的相等性。 |
BigInteger |
flipBit(int n)
返回其值与对此 BigInteger 进行指定位翻转后的值等效的 BigInteger。 |
float |
floatValue()
将此 BigInteger 转换为 float 。 |
BigInteger |
gcd(BigInteger val)
返回一个 BigInteger,其值是 abs(this) 和 abs(val) 的最大公约数。 |
int |
getLowestSetBit()
返回此 BigInteger 最右端(最低位)1 比特的索引(即从此字节的右端开始到本字节中最右端 1 比特之间的 0 比特的位数)。 |
int |
hashCode()
返回此 BigInteger 的哈希码。 |
int |
intValue()
将此 BigInteger 转换为 int 。 |
boolean |
isProbablePrime(int certainty)
如果此 BigInteger 可能为素数,则返回 true,如果它一定为合数,则返回 false。 |
long |
longValue()
将此 BigInteger 转换为 long 。 |
BigInteger |
max(BigInteger val)
返回此 BigInteger 和 val 的最大值。 |
BigInteger |
min(BigInteger val)
返回此 BigInteger 和 val 的最小值。 |
BigInteger |
mod(BigInteger m)
返回其值为 (this mod m) 的 BigInteger。 |
BigInteger |
modInverse(BigInteger m)
返回其值为 (this-1 mod m) 的 BigInteger。 |
BigInteger |
modPow(BigInteger exponent, BigInteger m)
返回其值为 (thisexponent mod m) 的 BigInteger。 |
BigInteger |
multiply(BigInteger val)
返回其值为 (this * val) 的 BigInteger。 |
BigInteger |
negate()
返回其值是 (-this) 的 BigInteger。 |
BigInteger |
nextProbablePrime()
返回大于此 BigInteger 的可能为素数的第一个整数。 |
BigInteger |
not()
返回其值为 (~this) 的 BigInteger。 |
BigInteger |
or(BigInteger val)
返回其值为 (this | val) 的 BigInteger。 |
BigInteger |
pow(int exponent)
返回其值为 (thisexponent) 的 BigInteger。 |
static BigInteger |
probablePrime(int bitLength,
Random rnd)
返回有可能是素数的、具有指定长度的正 BigInteger。 |
BigInteger |
remainder(BigInteger val)
返回其值为 (this % val) 的 BigInteger。 |
BigInteger |
setBit(int n)
返回其值与设置了指定位的此 BigInteger 等效的 BigInteger。 |
BigInteger |
shiftLeft(int n)
返回其值为 (this << n) 的 BigInteger。 |
BigInteger |
shiftRight(int n)
返回其值为 (this >> n) 的 BigInteger。 |
int |
signum()
返回此 BigInteger 的正负号函数。 |
BigInteger |
subtract(BigInteger val)
返回其值为 (this - val) 的 BigInteger。 |
boolean |
testBit(int n)
当且仅当设置了指定的位时,返回 true。 |
byte[] |
toByteArray()
返回一个 byte 数组,该数组包含此 BigInteger 的二进制补码表示形式。 |
String |
toString()
返回此 BigInteger 的十进制字符串表示形式。 |
String |
toString(int radix)
返回此 BigInteger 的给定基数的字符串表示形式。 |
static BigInteger |
valueOf(long val)
返回其值等于指定 long 的值的 BigInteger。 |
BigInteger |
xor(BigInteger val)
返回其值为 (this ^ val) 的 BigInteger。 |
code:
package lq2017_gs; import java.math.BigInteger; import java.util.Scanner; public class t4 { public static void main(String[] args) { Scanner cin = new Scanner(System.in); // int n = cin.nextInt(); int n = Integer.parseInt(cin.nextLine().trim()); int nowRadix = 10; String num = ""; // 存放数字 String ins = ""; // 存放当前进制 while(n-- != 0) { String nowline = cin.nextLine().trim(); if(nowline.contains(" ")) { String pre = nowline.split(" ")[0]; String last = nowline.split(" ")[1]; if(pre.equals("NUM")) { if(ins.equals("ADD")) { if(nowRadix == 10) { num = new BigInteger(num).add(new BigInteger(last)).toString(); } else { num = new BigInteger(num, nowRadix).add(new BigInteger(last, nowRadix)).toString(nowRadix); } } else if(ins.equals("SUB")) { if(nowRadix == 10) { num = new BigInteger(num).subtract(new BigInteger(last)).toString(); } else { num = new BigInteger(num, nowRadix).subtract(new BigInteger(last, nowRadix)).toString(nowRadix); } } else if(ins.equals("MUL")) { if(nowRadix == 10) { num = new BigInteger(num).multiply(new BigInteger(last)).toString(); } else { num = new BigInteger(num, nowRadix).multiply(new BigInteger(last, nowRadix)).toString(nowRadix); } } else if(ins.equals("DIV")) { if(nowRadix == 10) { num = new BigInteger(num).divide(new BigInteger(last)).toString(); } else { num = new BigInteger(num, nowRadix).divide(new BigInteger(last, nowRadix)).toString(nowRadix); } } else if(ins.equals("MOD")) { if(nowRadix == 10) { num = new BigInteger(num).mod(new BigInteger(last)).toString(); } else { num = new BigInteger(num, nowRadix).mod(new BigInteger(last, nowRadix)).toString(nowRadix); } } else { num = last; } } else if(pre.equals("CHANGE")){ if(nowRadix != Integer.parseInt(last)) { num = new BigInteger(num, nowRadix).toString(); nowRadix = Integer.valueOf(last); num = new BigInteger(num).toString(nowRadix); } } } else { if(nowline.equals("CLEAR")) { num = ""; } else if(nowline.equals("EQUAL")) { // System.out.println("test-equal"); System.out.println(num); } else if(nowline.equals("ADD")){ ins = "ADD"; } else { // System.out.println("test: " + nowline); System.out.println("指令错误!"); } } } } }
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,否则按无效代码处理。
---------------------
思路: 模拟吧。
注意:string 不好改变某个位置的值,而stringBuilder可以,但是stringBuilder传参数传的引用,所以会改变原来的值,
故在使用的时候要先copy一份!!!copy的方法不能只直接对象赋值,那样没用。
package lq2017_gs; import java.util.Scanner; public class t5 { public static void main(String[] args) { Scanner cin = new Scanner(System.in); int n = Integer.parseInt(cin.nextLine().trim()); while(n-- != 0) { StringBuilder str = new StringBuilder(cin.nextLine()); int ans = dfs(1, str); System.out.println(ans); } } public static int dfs(int f, StringBuilder st) { // 注意注意!!!st为引用对象,直接修改会改变原来的值!!!得copy一份!!! StringBuilder str = new StringBuilder(st.toString()); // 判断比赛结果 if(str.indexOf("LOL") != -1) { return -1; // 现在下的人输了 } if(str.indexOf("*") == -1) { return 0; // 平棋 } // 不同对象下子,都要达到利益最大化 int len = str.length(); int p = -1; // 标记是否能平棋 for(int i = 0; i < len; i++) { if(str.charAt(i) == '*') { // 空格可以下子 // 尝试第一种下法 str.setCharAt(i, 'L'); int ans = dfs(-f, str); if(ans == -1) { // 对方输了我就赢了 return 1; } else if(ans == 0) { p = i; } // 第一种没赢的话就尝试第二种下法 str.setCharAt(i, 'O'); ans = dfs(-f, str); if(ans == -1) { return 1; } else if(ans == 0) { p = i; } str.setCharAt(i, '*'); } } if(p == -1) { return -1; // 不能赢和平就是输 } else { return 0; } } } /* 4 *** L**L L**L***L L*****L */