1,以下内容皆为原创。
2,代码虽然用的是Java,但算法思想别无二致。
3,包含本次模拟赛10道题的思路,尽可能多的题解,和代码注释。
4,代码均为作者手敲,若有错误,优化或其它解法,望留言,共同进步。
答案:108
解析:单纯的一道数学题,和语言没关系。30个36像素的字总共是30*36=1080。那变成10像素就是 1080/10=108 个字。
public class Main {
public static void main(String[] args) {
System.out.println(36*30/10); //108
}
}
答案:608
解析:这道题数值太大,所以我们每算出来一步,就要进行取余。
public class Main {
public static void main(String[] args) {
int two=2;
int ans=1;
for (int i = 1; i <= 2023; i++) {
ans=(ans*two)%1000; //注意:这里对乘积的整体取余。
} //若写成 ans*=two%1000 ,它只对two取余了,所以是错的。
System.out.println(ans); //608
}
}
答案:4169
解析:本题考查高进制转低进制的一个经典之法--除基取余法。
public class Main {
public static void main(String[] args) {
int cnt=1;
int i=1;
while(cnt<25){
//十进制转二进制
int temp2=i;
int sum2=0;
while (temp2>0){
sum2+=temp2 % 2;
temp2 /= 2;
}
//十进制转八进制
int temp8=i;
int sum8=0;
while (temp8>0){
sum8+=temp8 % 8;
temp8 /= 8;
}
//判断二进制数位和与八进制数位和是否相等
if(sum2==sum8) {
System.out.print(cnt++ + " ");
System.out.println(i);
}
i++;
}
}
}
答案:901440
解析: 枚举,对每一个数的约数个数做统计,选出第一个最大的。
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int[][] arr = new int[6][6];
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 6; j++) {
arr[i][j]=sc.nextInt(); //将36个数读入数组中.
}
}
int max=0;
int maxNumber=0;
for (int[] row : arr){
for (int col : row){
int ans = getCount(col);
if(ans>max){ //严格大于才进去,保证是最先出现的最大数
max=ans;
maxNumber=col; //将最大数存起来
}
}
}
System.out.println(maxNumber);
}
public static int getCount(int n){
int cnt=0;
for (int i = 1; i <= n; i++) { //枚举,统计约数.
if(n%i==0) cnt++;
}
return cnt;
}
}
答案:591
解析:这个题,题目读起来语义不明的感觉,我的理解是第一行和第一列上的所有0变成2。 方法很多,最重要的是写的代码要考虑连通性,这是很致命的。下面给大家给出深搜,广搜,递归解法。
//深搜
public class Main {
static final int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; // 定义上下左右四个方向的偏移量
static int rows = 30;
static int cols = 40;
static int ans = 0;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int[][] matrix = new int[rows][cols];
for (int i = 0; i < rows; i++) {
String s = sc.next(); //这里不推荐使用nextLine()读取,因为它会读入空格,所以容易出错.
for (int j = 0; j < cols; j++) {
matrix[i][j] = Integer.parseInt(s.charAt(j)+""); //将字符串中单个字符提取出来变为数字添进数组中.
}
}
//统计
int twos = countTwos(matrix);
System.out.println(twos);
}
public static int countTwos(int[][] matrix) {
// 遍第一行,将值为0的元素及其相邻的0元素变为2
for (int i = 0; i < cols; i++) {
if (matrix[0][i] == 0) {
dfs(matrix, 0, i);
}
}
// 遍历第一列,将值为0的素及其相邻的0元素变为2
for (int i = 0; i < rows; i++) {
if (matrix[i][0] == 0) {
dfs(matrix, i, 0);
}
}
return ans;
}
private static void dfs(int[][] matrix, int row, int col) {
// 标记当前位置为2
matrix[row][col] = 2;
ans++;
// 遍历当前位置的上下左右四个相邻位置
for (int[] dir : dirs) {
int newRow = row + dir[0];
int newCol = col + dir[1];
// 判断新位置是否合法且为0,若是则递归调用dfs函数
if (newRow >= 0 && newRow < rows && newCol >= 0 && newCol < cols && matrix[newRow][newCol] == 0) {
dfs(matrix, newRow, newCol);
}
}
}
}
//广搜
public class Main {
static final int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; // 定义上下左右四个方向的偏移量
static int rows = 30;
static int cols = 40;
static int ans = 0; //累加统计
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int[][] matrix = new int[rows][cols];
for (int i = 0; i < rows; i++) {
String s = sc.next(); //这里不推荐使用nextLine()读取,因为它会读入空格,所以容易出错.
for (int j = 0; j < cols; j++) {
matrix[i][j] = Integer.parseInt(s.charAt(j)+""); //将字符串中单个字符提取出来变为数字添进数组中.
}
}
int twos = countTwos(matrix);
System.out.println(twos);
}
public static int countTwos(int[][] matrix) {
boolean[][] vis = new boolean[rows][cols]; // 用于记录节点是否已经被处理过
Queue<int[]> queue = new LinkedList<>(); // 创建队列
// 遍历第一行
for (int i = 0; i < cols; i++) {
if (matrix[0][i] == 0) {
queue.offer(new int[]{0, i}); // 将节点添加到队列中
matrix[0][i] = 2; // 将节点的值改为2
ans++;
vis[0][i] = true; // 标记节点为已处理
}
}
// 遍历第一列
for (int i = 0; i < rows; i++) {
if (matrix[i][0] == 0) {
queue.offer(new int[]{i, 0});
matrix[i][0] = 2;
ans++;
vis[i][0] = true;
}
}
while (!queue.isEmpty()) {
int[] curr = queue.poll(); // 弹出队列中的第一个节点
int row = curr[0];
int col = curr[1];
// 检查上下左右四个方向的位置
for (int[] dir : dirs) {
int newRow = row + dir[0];
int newCol = col + dir[1];
// 如果位置合法且值为0且未被处理过,则将其添加到队列中,将其值改为2,并标记为已处理
if (newRow >= 0 && newRow < rows && newCol >= 0 && newCol < cols && matrix[newRow][newCol] == 0 && !vis[newRow][newCol]) {
queue.offer(new int[]{newRow, newCol});
matrix[newRow][newCol] = 2;
ans++;
vis[newRow][newCol] = true;
}
}
}
return ans;
}
}
//递归
public class Main{
static int rows = 30; //行
static int cols = 40; //列
static int ans = 0;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int[][] matrix = new int[rows][cols];
for (int i = 0; i < rows; i++) {
String s = sc.next(); //这里不推荐使用nextLine()读取,因为它会读入空格,所以容易出错.
for (int j = 0; j < cols; j++) {
matrix[i][j] = Integer.parseInt(s.charAt(j)+""); //将字符串中单个字符提取出来变为数字添进数组中.
}
}
// 遍历第一列,将值为0的素及其相邻的0元素变为2
for (int i = 0; i < rows; i++) {
if (matrix[i][0] == 0) {
infect(matrix, i, 0);
}
}
// 遍第一行,将值为0的元素及其相邻的0元素变为2
for (int j = 0; j < cols; j++) {
if (matrix[0][j] == 0) {
infect(matrix, 0, j);
}
}
System.out.println(ans);
}
// 递归函数,将当前位置的周围0全部变为2
public static void infect(int[][] matrix, int i, int j) {
if (i < 0 || i >= rows || j < 0 || j >= cols || matrix[i][j] != 0) {
return;
}
matrix[i][j] = 2;
ans++;
infect(matrix, i-1, j); //上
infect(matrix, i+1, j); //下
infect(matrix, i, j-1); //左
infect(matrix, i, j+1); //右
}
}
解析:简单题,只需要想个方法,把第一个数放末尾就行。以下给出数位,数组,字符串的解题方法。
//数位
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int number = sc.nextInt(); //读入一个六位数
int digit1 = number / 100000; // 十万位
int digit2 = (number / 10000) % 10; // 万位
int digit3 = (number / 1000) % 10; // 千位
int digit4 = (number / 100) % 10; // 百位
int digit5 = (number / 10) % 10; // 十位
int digit6 = number % 10; // 个位
int result = digit2 * 100000 + digit3 * 10000 + digit4 * 1000 + digit5 * 100 + digit6 * 10 + digit1;
System.out.println(result);
}
}
//数组
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int number = sc.nextInt(); //读入一个六位数
//依次存在数组里
int[] arr = new int[6];
for (int i = arr.length-1; i >=0; i--) {
arr[i] = number % 10;
number /= 10;
}
//把第一个拿出来放最后
int temp=arr[0];
for (int i = 1; i < arr.length; i++) {
arr[i-1]=arr[i]; //依次往前挪移
}
arr[arr.length-1]=temp;
//遍历
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]);
}
}
}
//字符串
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.next();
//截取第一个字符拼接在末尾
String s1 = s.substring(0,1);
String s2 = s.substring(1);
System.out.println(s2+s1);
}
}
解析:首先用正向思维解题,由于每个字符串里的元音字母个数不同,所以我们用集合这种变长容器来存取,然后拿到最后一个元音字母。然后用逆向思维解题,从后往前看,就很简单了。
//有序集合
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.next();
//拿到最后一个元音字母
char lastVowel = getLastVowel(str);
System.out.println(lastVowel);
}
public static char getLastVowel(String str) {
List<Character> vowels = new ArrayList<>();
//依次遍历字符串,将元音字母存进有序集合.
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (isVowel(c)) {
vowels.add(c);
}
}
return vowels.get(vowels.size() - 1);
}
public static boolean isVowel(char c) {
return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
}
}
//逆向遍历
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
//读入字符串放在字符数组中
char[] s = sc.next().toCharArray();
//逆向思维,从后往前看
for (int i = s.length-1; i >=0 ; i--) {
if(s[i]=='a'||s[i]=='e'||s[i]=='i'||s[i]=='o'||s[i]=='u'){
System.out.println(s[i]);
break;
}
}
}
}
解析: 将乘积用一个临时变量保存,再赋给自己,迭代自己,直到自己小于10.
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(); //输入一个整数
while(n>=10){
int temp=n;
int ans=1;
while(temp>0){ //对临时变量进行数位乘积。
int digit=temp%10;
if(digit>0){
ans*=digit;
}
temp/=10;
}
System.out.println(ans);
n=ans; //把结果赋给本身,迭代自己。
}
}
}
解析:这道题和第五题的思想很类似,也是一道最大连通的问题,只是这道题是求存在>1约数的最大连通。下面给出深搜和递归。
//深搜
public class Main {
private static int n; //行
private static int m; //列
private static int[][] grid; //存储
private static boolean[][] visited; //标记
private static int answer; //统计
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
grid = new int[n][m];
visited = new boolean[n][m]; //此数组对走过的位置进行标记
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
grid[i][j] = sc.nextInt();
}
}
int r = sc.nextInt(); //起始位置的行
int c = sc.nextInt(); //起始位置的列
dfs(r - 1, c - 1); //变成数组对应的位置开始深搜
System.out.println(answer);
}
private static void dfs(int x, int y) {
if (visited[x][y]) {
return;
}
//标记,++
visited[x][y] = true;
answer++;
//判断左 下 右 上是否有存在 >1 约数的,有则继续深搜。
int[] dx = {-1, 0, 1, 0};
int[] dy = {0, 1, 0, -1};
for (int i = 0; i < 4; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
if (nx >= 0 && nx < n && ny >= 0 && ny < m && gcd(grid[x][y], grid[nx][ny]) > 1) {
dfs(nx, ny);
}
}
visited[x][y] = false;
}
//欧几里得算法
private static int gcd(int a, int b) {
if (b == 0) {
return a;
}
return gcd(b, a % b);
}
}
//递归
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(); //行
int m = sc.nextInt(); //列
int[][] grid = new int[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
grid[i][j] = sc.nextInt(); //向数组中读入元素
}
}
int r = sc.nextInt(); //起始位置的行
int c = sc.nextInt(); //起始位置的列
boolean[][] visited = new boolean[n][m]; //标记是否被访问
//递归调用并输出
System.out.println(getCount(grid, r-1, c-1, visited));
}
public static int getCount(int[][] grid, int r, int c, boolean[][] visited) {
// 如果当前方格已经访问过,则返回0
if (visited[r][c]) {
return 0;
}
// 标记当前方格为已访问
visited[r][c] = true;
// 计算可到达的方格数
int count = 1;
// 尝试向上移动
if (r > 0 && canMove(grid, r, c, r-1, c)) {
count += getCount(grid, r-1, c, visited);
}
// 尝试向下移动
if (r < grid.length-1 && canMove(grid, r, c, r+1, c)) {
count += getCount(grid, r+1, c, visited);
}
// 尝试向左移动
if (c > 0 && canMove(grid, r, c, r, c-1)) {
count += getCount(grid, r, c-1, visited);
}
// 尝试向右移动
if (c < grid[0].length-1 && canMove(grid, r, c, r, c+1)) {
count += getCount(grid, r, c+1, visited);
}
return count;
}
//移动判断
public static boolean canMove(int[][] grid, int r1, int c1, int r2, int c2) {
// 判断两个方格是否相邻
if (Math.abs(r1 - r2) + Math.abs(c1 - c2) != 1) {
return false;
}
// 判断两个方格的最大公约数是否大于1
if (gcd(grid[r1][c1], grid[r2][c2]) > 1) {
return true;
}
return false;
}
//欧几里得算法
public static int gcd(int a, int b) {
if (b == 0) {
return a;
}
return gcd(b, a % b);
}
}
解析:这道题的思想并不难,只需要确定好固定的滑动窗口,然后一次枚举就行。只是在求滑动窗口内的和的时候,要考虑先求还是后求,后求类似于在线,时间复杂度会高一点。而先求类似于离线,时间复杂度会好很多。
//在线
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(); //长度
int k = sc.nextInt(); //窗口大小
int[] arr = new int[n];
for(int i=0; i<n; i++) arr[i]=sc.nextInt(); //读入
//存储最大值
int max=0;
for (int i = 0; i < n - k; i++) { //依次枚举
int sum=0;
for (int j = i; j < k + i; j++) { //确定固定的滑动窗口
sum+=arr[j]; //在线累加窗口中所有和
}
max=max > sum ? max : sum; //三元运算符比大小
}
System.out.println(max);
}
}
//离线
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(); //长度
int k = sc.nextInt(); //窗口大小
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i]=sc.nextInt(); //读入
}
//初始化sum为0,先累加窗口内的和
int sum = 0;
for (int i = 0; i < k; i++) {
sum += arr[i];
}
//初始化maxSum为sum
int maxSum = sum;
for (int i = k; i < n; i++) {
//从第k+1个元素开始遍历数组a
//每次将sum减去上一个连续k个元素的第一个元素,并加上当前连续k个元素的最后一个元素,更新sum
sum = sum - arr[i - k] + arr[i];
//maxSum用于存储连续k个元素的和的最大值
maxSum = Math.max(maxSum, sum);
}
System.out.println(maxSum);
}
}