蓝桥杯历年真题题目及题解目录汇总(推荐)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
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
*/