第十五届蓝桥杯模拟赛(第二期)题解
提前说明:作者是个菜鸡,不保证全部能ac
填空题
第一题和第二题有手就行
public class Main {
public static void main(String[] args) {
int j = 1;
for (int i = 1; j <= 23; i++) {
String bin = Integer.toBinaryString(i);
String oct = Integer.toOctalString(i);
int bi = sum(bin);
int oi = sum(oct);
if (bi == oi) {
System.out.println("第" + j + "个数:" + i);
j++;
}
}
}
static int sum(String str) {
int total = 0;
for (int i = 0; i < str.length(); i++) {
total += str.charAt(i) - '0';
}
return total;
}
}
import java.util.LinkedList;
import java.util.List;
public class Main {
public static int[] nums = {
393353, 901440, 123481, 850930, 423154, 240461,
373746, 232926, 396677, 486579, 744860, 468782,
941389, 777714, 992588, 343292, 385198, 876426,
483857, 241899, 544851, 647930, 772403, 109929,
882745, 372491, 877710, 340000, 659788, 658675,
296521, 491295, 609764, 718967, 842000, 670302
};
public static void main(String[] args) {
int max = 0;
int maxNum = 0;
for (int i = 0; i < nums.length; i++) {
int di = ds(nums[i]);
if (di > max) {
max = di;
maxNum = nums[i];
}
System.out.println("值:" + nums[i]);
System.out.println("约数个数:" + di);
}
System.out.println("最大值:" + maxNum);
System.out.println("约数个数:" + max);
}
/*
当时写的时候总感觉答案不对劲,就多写了几个求约数的函数
*/
// 求约数个数 3
static int ds(int n) {
int total = 0;
for (int i = 1; i <= n; i++) {
if (n % i == 0)
total++;
}
return total;
}
// 求约数个数 1
public static int divisors(int n) {
int[] cnt = new int[1000000 + 10];
for (int i = 2; i <= n / i; i++) {
if (n % i == 0) {
while (n % i == 0) {
n /= i;
cnt[i]++;
}
}
}
if (n > 1) {
cnt[n]++;
}
int total = 1;
for (int i = 0; i < cnt.length; i++) {
total = total * (cnt[i] + 1);
}
return total;
}
// 求约数个数 2
static int divs(int n) {
int t = 0;
List<Integer> list = new LinkedList<>();
for (int i = 1; i <= n / i; i++) {
if (n % i == 0) {
t++;
list.add(i);
if (i != n / i) {
t++;
list.add(n / i);
}
}
}
list.forEach(s -> System.out.print(s + " "));
System.out.println();
return t;
}
}
这道题我使用的是BFS
import java.util.LinkedList;
import java.util.Queue;
public class Main {
// bfs
static final int N = 30 + 10;
static int n = 30;
static int m = 40;
static boolean[][] state = new boolean[n + 1][m + 1];
static int[][] g = new int[n + 1][m + 1];
static String str =
"0000100010000001101010101001001100000011" +
"0101111001111101110111100000101010011111" +
"1000010000011101010110000000001011010100" +
"0110101010110000000101100100000101001001" +
"0000011010100000111111001101100010101001" +
"0110000110000000110100000000010010100011" +
"0100110010000110000000100010000101110000" +
"0010011010100110001111001101100110100010" +
"1111000111101000001110010001001011101101" +
"0011110100011000000001101001101110100001" +
"0000000101011000010011111001010011011100" +
"0000100000011001000100101000111011101100" +
"0010110000001000001010100011000010100011" +
"0110110000100011011010011010001101011011" +
"0000100100000001010000101100000000000010" +
"0011001000001000000010011001100101000110" +
"1110101000011000000100011001001100111010" +
"0000100100111000001101001000001010010001" +
"0100010010000110100001100000110111110101" +
"1000001001100010011001111101011001110001" +
"0000000010100101000000111100110010101101" +
"0010110101001100000100000010000010110011" +
"0000011101001001000111011000100111010100" +
"0010001100100000011000101011000000010101" +
"1001111010010110011010101110000000101110" +
"0110011101000010100001000101001001100010" +
"1101000000010010011001000100110010000101" +
"1001100010100010000100000101111111111100" +
"1001011010101100001000000011000110110000" +
"0011000100011000010111101000101110110001";
public static void main(String[] args) {
// 转为矩阵
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
// 二维坐标转为一维坐标
int k = (i - 1) * 40 + (j - 1);
g[i][j] = str.charAt(k) - '0';
}
}
Node start = new Node(1, 1);
// 第1行第1列的0修改为2
g[start.x][start.y] = 2;
bfs(start);
// 遍历矩阵,一共有多少个2
int two = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
System.out.print(g[i][j] + " ");
if (g[i][j] == 2)
two++;
}
System.out.println();
}
System.out.println(two);
}
static class Node {
public int x;
public int y;
public Node(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public String toString() {
return String.valueOf(x) + y;
}
}
static void bfs(Node start) {
Queue<Node> q = new LinkedList<>();
// 将开始节点入队
q.add(start);
state[start.x][start.y] = true;
int[] dx = {-1, 1, 0, 0};
int[] dy = {0, 0, -1, 1};
while (!q.isEmpty()) {
Node top = q.remove();
// 如果当前点的值=2
if (g[top.x][top.y] == 2) {
// 向当前点的上下左右4个方向搜索
// 找到0,把0变为2,入队
for (int i = 0; i < 4; i++) {
int x = top.x + dx[i];
int y = top.y + dy[i];
// 有没有出界
if (x >= 1 && x <= n && y >= 1 && y <= m) {
// 每个点只访问一次
if (state[x][y] != true) {
state[x][y] = true;
if (g[x][y] == 0) {
g[x][y] = 2;
q.add(new Node(x, y));
}
}
}
}
}
}
}
// 赛后想了下,这题也可以用dfs来写的
static void dfs(int x) {
if (x == n + 1)
return;
int[] dx = {-1, 1, 0, 0};
int[] dy = {0, 0, -1, 1};
// 在当前层中,遍历每一列,找到=2的格子
for (int y = 1; y <= m; y++) {
// 如果当前格子=2
if (g[x][y] == 2) {
// 向当前格子的上下左右四个方向搜索=0的格子
// 可以先假设先向下搜索,等到向下走不通,回溯之后再向当前点的其他方向搜索
// 顺便画个图,好理解点
for (int i = 0; i < 4; i++) {
int x1 = x + dx[i];
int y1 = y + dy[i];
// 判断边界
if (x1 >= 1 && x1 <= n && y1 >= 1 && y1 <= m) {
// 如果有0的格子,把这个格子变为2
if (g[x1][y1] == 0 && !state[x1][y1]) {
g[x1][y1] = 2;
state[x1][y1] = true;
// 向下一层搜索
dfs(x1);
state[x1][y1] = false;
}
}
}
}
}
}
}
大题
这是循环移动一个数的十万位的那题,题目没保存下来
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
public class Main {
static StreamTokenizer streamTokenizer = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static int nextInt() {
try {
streamTokenizer.nextToken();
} catch (IOException e) {
throw new RuntimeException(e);
}
return (int) streamTokenizer.nval;
}
public static void main(String[] args) {
int x = nextInt();
String str = Integer.toString(x);
StringBuilder sb = new StringBuilder(str);
// 将第一位数插入到数的末尾
sb.insert(6, str.charAt(0));
// 将第一位数删去
sb.delete(0, 1);
System.out.println(sb);
}
}
问题描述
给定一个序列 a[1], a[2], …, a[n] ,如果对于某个下标 i ,a[i+1]<a[i],则称序列在 i 到 i+1 这个位置下落,落差为 a[i]-a[i+1] 。
请问序列的最大落差是多少?
输入格式
输入的第一行包含一个整数 n ,表示序列的长度。
第二行包含 n 个整数,相邻的整数之间使用一个空格分隔,表示给定的序列。
输出格式
输出一行包含一个整数,表示答案。如果没有位置下落,输出 0 。
样例输入
5
4 5 3 9 6
样例输出
3
评测用例规模与约定
对于所有评测用例,1 <= n <= 1000,0 <= a[i] <= 10000。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
public class Main {
static final int N = 1000 + 10;
static int[] a = new int[N];
static StreamTokenizer streamTokenizer = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static int nextInt() {
try {
streamTokenizer.nextToken();
} catch (IOException e) {
throw new RuntimeException(e);
}
return (int) streamTokenizer.nval;
}
public static void main(String[] args) {
int n = nextInt();
for (int i = 1; i <= n; i++) {
a[i] = nextInt();
}
int max = 0;
for (int i = 1; i <= n; i++) {
if (a[i] < a[i - 1]) {
max = Math.max(max, a[i - 1] - a[i]);
}
}
System.out.println(max);
}
}
问题描述
输入一个仅包含小写英文字母的字符串,请问这个字符串中的最后一元音是什么。
在英文中,a, e, i, o, u 共 5 个字母是元音字母,其它字母不是元音字母。
输入格式
输入一行包含一个字符串,仅由小写英文字符组成,字符串中至少包含一个元音字母。
输出格式
输出一行包含一个字符,表示答案。
样例输入
lanqiao
样例输出
o
样例输入
cup
样例输出
u
评测用例规模与约定
对于所有评测用例,1 <= 字符数量 <= 10000 。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
char[] arr = str.toCharArray();
for (int i = arr.length - 1; i >= 0; i--) {
char c = arr[i];
if (
c == 'a' ||
c == 'e' ||
c == 'i' ||
c == 'o' ||
c == 'u'
) {
System.out.println(c);
return;
}
}
}
}
问题描述
给定一个整数,对这个整数的一次转换是指将这个整数变为这个整数的所有数位上的非零数字的乘积。
例如,对 123456789 进行一次转换变为 123456789=362880,再进行一次转换变为 36288=2304,再进行一次转换变为 234=24,再进行一次转换变为 8。
给定一个整数,请依次将转换过程中经历的每个整数输出,直到小于 10 。
输入格式
输入一行包含一个整数 n 。
输出格式
输出多行,每行包含一个整数。
样例输入
123456789
样例输出
362880
2304
24
8
评测用例规模与约定
对于 50% 的评测用例,1 <= n <= 10^9 (10的9次方)。
对于所有评测用例,1 <= n <= 10^18 (10的18次方)。
// 这段代码我感觉会超时
// 但是没想好如何去优化
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
long n = sc.nextLong();
while (n >= 10) {
String s = String.valueOf(n);
int len = s.length();
char[] a = s.toCharArray();
long res = 1;
for (int i = 0; i < len; i++) {
if (a[i] != '0')
res *= (a[i] - '0');
}
System.out.println(res);
n = res;
}
}
}
问题描述
小蓝站在一个 n 行 m 列的方格图中间,方格图的每一个方格上都标有一个正整数。
如果两个相邻方格(上下左右四个方向相邻)内的数的最大公约数大于 1 ,则可以从其中一个方格移动到另一个方格,当然也可以从另一个方格移回第一个方格。
假设小蓝开始时站在第 r 行第 c 列,请问小蓝可以移动到方格图内的多少个方格?
输入格式
输入的第一行包含两个整数 n, m ,用一个空格分隔,表示方格图的行数和列数。
接下来 n 行,每行包含 m 个正整数,相邻整数间用一个空格分隔,依次表示方格图中从第 1 行到第 n 行,每行从第 1 列到第 m 列中的数。
接下来一行包含两个整数 r, c,用一个空格分隔,表示小蓝所在的行号和列号。
输出格式
输出一行包含一个整数,表示答案。
样例输入
3 4
3 6 5 5
2 4 3 5
7 8 3 8
3 2
样例输出
5
评测用例规模与约定
对于50%的评测用例,1 <= n, m <= 100,方格图中的每个数不超过 10^5 (10的5次方)。
对于所有评测用例,1 <= n, m <= 1000,方格图中的每个数不超过 10^9 (10的9次方)。
// bfs搜索
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.LinkedList;
import java.util.Queue;
public class Main {
static StreamTokenizer streamTokenizer = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static int nextInt() {
try {
streamTokenizer.nextToken();
} catch (IOException e) {
throw new RuntimeException(e);
}
return (int) streamTokenizer.nval;
}
static final int N = 1000 + 10;
// n行m列
static int n, m;
// 邻接矩阵存图
static int[][] g = new int[N][N];
// 标记每一个点的访问状态(以访问/未访问)
static boolean[][] state = new boolean[N][N];
// 可以移动到的方格个数
static int total = 0;
public static void main(String[] args) {
n = nextInt();
m = nextInt();
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
g[i][j] = nextInt();
}
}
int r = nextInt();
int c = nextInt();
Node start = new Node(r, c);
bfs(start);
System.out.println(total);
}
static class Node {
public int x;
public int y;
public Node(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public String toString() {
return String.valueOf(x) + y;
}
}
/**
* 判断当前格子能否移动到相邻格子
* @param n1
* @param n2
* @return
*/
static boolean canMove(Node n1, Node n2) {
int num1 = g[n1.x][n1.y];
int num2 = g[n2.x][n2.y];
int g = gcd(num1, num2);
// 最大公约数>1 就能移动过去
return g > 1;
}
/**
* 求两个数的 最大公约数
*
* @param a
* @param b
* @return
*/
static int gcd(int a, int b) {
if (a < b)
return gcd(b, a);
if (a % b == 0)
return b;
return gcd(b, a % b);
}
/**
* bfs
* @param start
*/
static void bfs(Node start) {
Queue<Node> q = new LinkedList<>();
// 把起点加入到队列
q.add(start);
// 标记该点已经使用
state[start.x][start.y] = true;
// 因为可以从某一个方格移回第一个方格
// 所以可以移动到的方格个数+1
total++;
int[] dx = {-1, 1, 0, 0};
int[] dy = {0, 0, -1, 1};
while (!q.isEmpty()) {
Node top = q.remove();
// 向当前点的上下左右4个方向搜索
// 找到和当前格子公约数大于1的格子
for (int i = 0; i < 4; i++) {
int x = top.x + dx[i];
int y = top.y + dy[i];
Node newNode = new Node(x, y);
// 判断有没有出界
if (x >= 1 && x <= n && y >= 1 && y <= m) {
// 每个格子只会访问一次(剪枝)
if (!state[x][y]) {
state[x][y] = true;
if (canMove(top, newNode)) {
total++;
q.add(newNode);
}
}
}
}
}
}
}
对于这道题可以画个图来模拟思路
注意: 可以从某一个方格移回第一个方格,但我在图中没有标注。