JavaB group real questions of the 13th Blue Bridge Cup Provincial Competition (Java problem solution analysis)

foreword

150 points in total

The first problem-solving process:

A:+0分(答案算错了(计算得6,最终答案为7),想到是采用步骤做取余计算,但是没有使用多个样例来进行测试,就直接取答案了。)
B:+0分(答案算错了(计算得644,最终答案为3138)),我裂开,题意看错了,前一半是进行升序(实际上可以<=,我看成是只能<),实际上我们只需要对每一个字符判断前面一半是升序 && 是回文即可解决。(60秒)
C:+10分
D:+1(10个案例点就过了1个)
E:+0(本来认为是找规律题,没想到考的是算数基本定理)
F:+1.5(写了个暴力,优化需要使用优先队列 使用空间换时间)
G:+10(写了递归搜索就过了5个用例,优化使用DP)
I:
J:

The 13th Blue Bridge Cup Provincial Competition JavaB group real questions

Question A: Calculation of Weeks (5 points)

topic

image-20230311155421104

answer

Answer: 7

Solution 1: Step remainder calculation (int is enough)

public class Main {
    
    
	public static void main(String[] args) {
    
    
		int temp = 20;
		// 循环22次
		for (int i = 1; i <= 21; i++) {
    
    
			temp = (temp * 20) % 7;
		}
		// 打印最终结果
		// 其中(5 + temp) % 7是计算得到目标星期x的x下标(从0开始的),所以最后要进行+1。
		System.out.println((5 + temp) % 7 + 1);
	}
}

Solution 2: Use the API

① Use Math.pow directly

public class Main {
    
    
	public static void main(String[] args) {
    
    
		System.out.println(Math.pow(20, 22) % 7 + 6);
	}
}

② Use BigInteger

import java.math.BigInteger;

public class Main {
    
    
	public static void main(String[] args) {
    
    
		BigInteger bg = new BigInteger("20");
		//pow取次方数,remainder进行取余
		bg = bg.pow(22).remainder(BigInteger.valueOf(7)).add(BigInteger.valueOf(6));
		System.out.println(bg);
	}
}

image-20230311161038958


Question B: Mountains (5 points)

topic

image-20230311170747956

answer

Since this question is a fill-in-the-blank question, you can directly write violence to calculate the answer.

Violence method: enumerate [2022, 2022222022], check mountain type increment and decrement and palindrome.

Solution 1: Violence

Non-calling API version:

public class Main {
    
    

	public static boolean huiwen(int num) {
    
    
		char[] chs = String.valueOf(num).toCharArray();
		for (int l = 0, r = chs.length - 1; l <= r; l++, r--) {
    
    
			if (chs[l] != chs[r])
				return false;
		}
		return true;
	}

	public static boolean islianxu(int num) {
    
    
		char[] chs = String.valueOf(num).toCharArray();
		int n = chs.length;
		int b1 = n % 2 == 1 ? n / 2 : n / 2 - 1;
		int b2 = n / 2;
		// [0, b1] 单调增
		for (int i = 1; i <= b1; i++) {
    
    
			if (chs[i] <= chs[i - 1])
				return false;
		}
		// [b2, n - 1]单调减
		for (int i = b2 + 1; i < n; i++) {
    
    
			if (chs[i] >= chs[i - 1])
				return false;
		}
		return true;
	}

	public static void main(String[] args) {
    
    
		long start = System.currentTimeMillis();
		int ans = 0;
		for (int i = 2022; i <= 2022222022; i++) {
    
    
			if (islianxu(i) && huiwen(i)) {
    
    
				ans++;
			}
		}
		System.out.println(ans);
		long end = System.currentTimeMillis();
		System.out.println("" + ((double) (end - start) / 1000) + "秒");
	}
}  

image-20230311170421343

Call the API version:

public class Main {
    
    

	// 只需要比较前半部分
	public static boolean islianxu(int num) {
    
    
		char[] arr = String.valueOf(num).toCharArray();
		int n = arr.length;
		int len = n % 2 == 0 ? n / 2 - 1 : n / 2;
		// 比较前半部分
		for (int i = 1; i <= len; i++) {
    
    
			if (arr[i] < arr[i - 1])
				return false;
		}
		return true;
	}

	// 反转字符串来进行比较(判断是否是回文)
	public static boolean huiwen(int num) {
    
    
		String targetStr = (new StringBuilder(num + "")).reverse().toString();
		return String.valueOf(num).equals(targetStr);
	}

	public static void main(String[] args) {
    
    
		long start = System.currentTimeMillis();
		int ans = 0;
		for (int i = 2022; i <= 2022222022; i++) {
    
    
			if (islianxu(i) && huiwen(i)) {
    
    
				ans++;
			}
		}
		System.out.println(ans);
		long end = System.currentTimeMillis();
		System.out.println("" + ((double) (end - start) / 1000) + "秒");
	}
}

image-20230311170137375

Question C: Character Statistics (10 points)

topic

Blue Bridge Cup official website question - character statistics

image-20230311171142894

Solution (hash)

Hash goes through it again.

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Main {
    
    

	static final BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));

	public static void main(String[] args) throws Exception {
    
    
		int[] cnts = new int[26];
		String str = cin.readLine();
		char[] chs = str.toCharArray();
		int max = 0;
		for (char ch : chs) {
    
    
			cnts[ch - 'A']++;
			max = Math.max(cnts[ch - 'A'], max);
		}
		for (int i = 0; i < 26; i++) {
    
    
			if (cnts[i] == max) {
    
    
				System.out.printf("%c", (char) (i + 'A'));
			}
		}
	}
}

Local debugging:

image-20230303174858319

Submitted by the official website of the Blue Bridge Cup:

image-20230311163327737


Question D: Minimum number of questions (10 points)

topic

Blue Bridge Cup official website questions - the minimum number of questions

image-20230311171540816

image-20230311171548836

answer

Topic requirements: The number of students who have done more questions than him does not exceed the number of students who have done fewer questions than him. More <= less.

Solution 1: Violence (sorting), the time complexity is all in sorting, and the time complexity of determining that n children do more is O(n).

思路:
1、对所有小朋友做的题数进行排序
2、确定一个中间值target,分别使用两个计数变量(l、r)记录>target与<target的个数。
3、若是l == r,那么我们直接将<target的值增加到target即可;若是l<r,那么此时我们需要将目标值放到target+1上,此时r<=l(必然情况)
4、枚举每一个小朋友的解题数与target作比较,若是>=target那么即可直接输出0,若是<target则需要进行分情况讨论:讨论关于l == r ? 1 : 0
		情况1:12778  target = 7, l = 2 r = 1, 此时a[i] = 2时,我们只需要7-2即可
        情况2: 77788  target = 8(由于l < r,增加1), l = 0, r = 2, 此时a[i] = 7,为8-7即可
        情况3: 11788,target = 7,l = 2, r = 2,此时a[i] = 1,我们需要将a[i]提升到target+1,才能保证r<=l

Solution 1: Sort (over 7 points)

Complexity analysis: time complexity O(n.logn); space complexity O(n)

import java.util.*;
import java.io.*;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main {
    
    
    static final BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
    static final PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out));
    static final int N = 100010;
    static int[] a = new int [N];
    static int n;

    public static void main(String[] args) throws Exception{
    
    
        n = Integer.parseInt(cin.readLine());
        String[] ss = cin.readLine().split(" ");
        for (int i = 0; i < n; i ++) {
    
    
          a[i] = Integer.parseInt(ss[i]);
        }
        //克隆,来进行排序
        int[] temp = a.clone();
        Arrays.sort(temp, 0, n);
        //target:目标值,l:比target小的数量,r:比target大的数量
        int target = temp[n / 2], l = 0, r = 0;
        for (int i = 0; i < n; i ++) {
    
    
          if (temp[i] > target) {
    
    
              r ++;
          }else if (temp[i] < target) {
    
    
              l ++;
          }
        }
        //由于我们本身就是取的排序中间值,若是大于中间值的数量  >  小于中间值的数量
        //那么我们的目标值就需要进行+1
        if (l < r) target ++;
        //接着来进行输出结果
        for (int i = 0; i < n; i ++) {
    
    
          if (a[i] >= target) {
    
    
            out.printf("%d ", 0);
          }else {
    
    
            //考虑到将当前值提升到target 还是 target+1(取决于左右两边>与<数的情况)
            //当前的值为a[i] < target,讨论关于
            //情况1:12778  target = 7, l = 2 r = 1, 此时a[i] = 2时,我们只需要7-2即可
            //情况2: 77788  target = 8(由于l < r,增加1), l = 0, r = 2, 此时a[i] = 7,为8-7即可
            //情况3: 11788,target = 7,l = 2, r = 2,此时a[i] = 1,我们需要将a[i]提升到target+1,才能保证r<=l
            out.printf("%d ", target - a[i] + (l == r ? 1 : 0));
          }
        }
        out.flush();
    }
}

image-20230311180743531


Question E: Finding factorial (15 points)

topic

image-20230311185331445

image-20230311185341257

answer

According to the fundamental theorem of arithmetic, a number can be decomposed into the product of several numbers.

n! = N = P1a1 P2a2 P3a3 * ... Pnan, what needs to be counted in this question is the number of consecutive 0s in the suffix, then it is the number of factorials of 10 in the target n!, and 10 = 2 * 5, I want to get the target 10, then we need to match many pairs of 2 and 5. At this time, we need to find min (number of prime factors 2, number of prime factors 5), and the number of prime factors 2 is greater than 5. So we can directly find the number with a prime factor of 5 == k.

For a number n, to find the number of n! whose prime factor is 5, we only need to divide n continuously to get it.

//计算n中有多少个5
public static long check(int num) {
    
    
    long res = 0L;
    while (num > 0) {
    
    
        res += num / 5;
        num /= 5;
    }
    return res;
}

Solution 1: Enumerate 1-10 8 , each number represents a factorial, come and go to find out whether the value of the factorial is >=k, find the first and smallest n is the answer.

  • The purpose of enumerating to 10 8 here is because the time complexity is O(n.logn), and the number of calculations is 100 million times, which is almost 1 second, so the value at the critical position can be taken here.

Solution 2: Since the results obtained by checking 1-10 8 are incremental, the enumeration process can be modified to binary search. At this time, the complexity can be directly optimized to O(logn.logn), directly ac.


Solution 1: Fundamental Theorem of Arithmetic + Enumeration (over 5 points)

Complexity analysis: time complexity O(n.logn); space complexity

import java.util.*;
import java.io.*;

public class Main {
    
    

    static final Scanner cin = new Scanner(System.in);
    static long N = (long)1e8;
    static long k;

    //计算n中有多少个5
    public static long check(int num) {
    
    
        long res = 0L;
        while (num > 0) {
    
    
            res += num / 5;
            num /= 5;
        }
        return res;
    }

    public static void main(String[] args) {
    
    
        k = cin.nextLong();
        for (int i = 1; i <= N; i ++) {
    
    
            //找到第一个>=k情况
            long res = check(i);
            if (res >= k) {
    
    
                if (res == k) System.out.println(i);
                else System.out.println(-1);
                return;
            }
        }
        System.out.println(-1);
    }
}

image-20230311202306316


Solution 2: Dichotomy + Fundamental Theorem of Arithmetic

Complexity analysis: time complexity O(logn*logn); space complexity O(1)

import java.util.*;
import java.io.*;

public class Main {
    
    

    static final Scanner cin = new Scanner(System.in);
    static long k;

    //计算n中有多少个5
    public static long check(long num) {
    
    
        long res = 0L;
        while (num > 0) {
    
    
            res += num / 5;
            num /= 5;
        }
        return res;
    }

    public static void main(String[] args) {
    
    
        k = cin.nextLong();
        //二分
        long l = 0, r = (long)9e18;
        while (l < r) {
    
    
            long mid = l + r >> 1;
            if (check(mid) >= k) r = mid;
            else l = mid + 1;
        }
        if (check(r) == k) {
    
    
            System.out.println(r);
        }else {
    
    
            System.out.println("-1");
        }
    }
}

image-20230311202542184


Question F: Maximum Submatrix (15 points)

topic

image-20230311202701071

image-20230311202738271

image-20230311202750297

image-20230311202806227

answer

Solution 1: Violence (over 10% data)

The maximum number of data matrix blocks is 100,000

law of violence

Complexity analysis: time complexity O(n 6 ); space complexity O(n*m)

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Main {
    
    
	static final BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
	static final int N = 90, M = 100010;
	static int[][] a = new int[N][M];
	static int n, m, limit;

	public static void main(String[] args) throws Exception {
    
    
		String[] ss = cin.readLine().split(" ");
		n = Integer.parseInt(ss[0]);
		m = Integer.parseInt(ss[1]);
		for (int i = 1; i <= n; i++) {
    
    
			ss = cin.readLine().split(" ");
			for (int j = 1; j <= m; j++) {
    
    
				a[i][j] = Integer.parseInt(ss[j - 1]);
			}
		}
		limit = Integer.parseInt(cin.readLine());
		int ans = 0;
		// 暴力
		for (int i = 1; i <= n; i++) {
    
    
			for (int j = 1; j <= m; j++) {
    
    
				// 枚举目标点
				for (int x = i; x <= n; x++) {
    
    
					for (int y = j; y <= m; y++) {
    
    
						// 遍历区间 起始(i, j) - (x, y)
						int max = 0, min = 0, s = 0;
						for (int xx = i; xx <= x; xx++) {
    
    
							for (int yy = j; yy <= y; yy++) {
    
    
								s++;// 数量
								max = Math.max(max, a[xx][yy]);
								min = Math.min(min, a[xx][yy]);
							}
						}
						if (max - min <= limit) {
    
    
							ans = Math.max(ans, s);
						}
					}
				}
			}
		}
		System.out.println(ans);
	}
}

test:

3 4
2 0 7 9
0 6 9 7
8 4 6 4
8

image-20230306113359549

Solution 2: Monotonic queue (learning)

Official Solution-Learning

Pruning in the middle, using space in the middle for time

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Main {
    
    
	static final BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
	static final int N = 90, M = 100010;
	static int[][] a = new int[N][M];
	// 前缀和(最大值,最小值)
	static int[][] max = new int[N][M], min = new int[N][M];
	static int n, m, limit;

	public static void main(String[] args) throws Exception {
    
    
		String[] ss = cin.readLine().split(" ");
		n = Integer.parseInt(ss[0]);
		m = Integer.parseInt(ss[1]);
		for (int i = 1; i <= n; i++) {
    
    
			ss = cin.readLine().split(" ");
			for (int j = 1; j <= m; j++) {
    
    
				a[i][j] = Integer.parseInt(ss[j - 1]);
				int preMax = Math.max(Math.max(max[i - 1][j], max[i][j]), max[i - 1][j - 1]);
				max[i][j] = Math.max(preMax, a[i][j]);
				int preMin = Math.max(Math.max(min[i - 1][j], min[i][j]), min[i - 1][j - 1]);
				min[i][j] = Math.max(preMin, min[i][j]);
			}
		}
		limit = Integer.parseInt(cin.readLine());
		// 遍历整个矩阵
		int ans = 0;
		// 枚举所有行
		for (int i = 1; i <= n; i++) {
    
    
			for (int j = i; j <= n; j++) {
    
    
				// 左右指针
				for (int l = 1, r = 1, s = 0, mmax = 0, mmin = 0; r <= m; r++) {
    
    
					// 个数增加
					s += j - i + 1;
					// 矩阵范围最大值确定
					
				}
			}
		}
	}
}

Question G: Array Segmentation (20 points)

topic

image-20230311210253153

image-20230311210304718

image-20230311210317382

answer

Solution 1: Violent enumeration (over 5 points)

image-20230311135618848

Brute force solution: print with path

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class Main {
	static final BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
	static final int N = 10010;
	static int[] a = new int[N];
	static int n;
	static int ans;

	public static void dfs(int start, int step, List<Integer> res) {
		// 若是start + step > n,越界无法判断,直接结束
		if (start + step > n)
			return;
		// 判断[start, start + step)区间是否是连续
		int max = a[start], min = a[start];
		for (int i = start; i < start + step; i++) {
			max = Math.max(a[i], max);
			min = Math.min(a[i], min);
		}
		// 若是当前无法构成连续区间直接结束
		if (step != 1 && (max - min + 1) != step) {
			return;
		}
		// 表示区间连续
		// 若是此时start+step == n,此时表示构成连续区间
		if (start + step == n) {
			ans++;
			System.out.println(res);
			return;
		}
		// 递归处理,不同的情况
		for (int sstep = 1; sstep <= n; sstep++) {
			res.add(sstep);
			dfs(start + step, sstep, res);
			res.remove(res.size() - 1);
		}
	}

	public static void main(String[] args) throws Exception {
		n = Integer.parseInt(cin.readLine());
		String[] ss = cin.readLine().split(" ");
		for (int i = 0; i < n; i++) {
			a[i] = Integer.parseInt(ss[i]);
		}
		// 起始步骤枚举
		for (int step = 1; step <= n; step++) {
			ArrayList<Integer> res = new ArrayList<>();
			res.add(step);
			dfs(0, step, res);
		}
		System.out.println(ans);
	}
}

image-20230311135239670

Brute force solution: print without path

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;

public class Main {
    
    
	static final BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
	static final int N = 10010;
	static int[] a = new int[N];
	static int n;
	static int ans;

	public static void dfs(int start, int step) {
    
    
		// 若是start + step > n,越界无法判断,直接结束
		if (start + step > n)
			return;
		// 判断[start, start + step)区间是否是连续
		int max = a[start], min = a[start];
		for (int i = start; i < start + step; i++) {
    
    
			max = Math.max(a[i], max);
			min = Math.min(a[i], min);
		}
		// 若是当前无法构成连续区间直接结束
		if (step != 1 && (max - min + 1) != step) {
    
    
			return;
		}
		// 表示区间连续
		// 若是此时start+step == n,此时表示构成连续区间
		if (start + step == n) {
    
    
			ans++;
			return;
		}
		// 递归处理,不同的情况
		for (int sstep = 1; sstep <= n; sstep++) {
    
    
			dfs(start + step, sstep);
		}
	}

	public static void main(String[] args) throws Exception {
    
    
		n = Integer.parseInt(cin.readLine());
		String[] ss = cin.readLine().split(" ");
		for (int i = 0; i < n; i++) {
    
    
			a[i] = Integer.parseInt(ss[i]);
		}
		// 起始步骤枚举
		for (int step = 1; step <= n; step++) {
    
    
			ArrayList<Integer> res = new ArrayList<>();
			res.add(step);
			dfs(0, step);
		}
		System.out.println(ans);
	}
}

image-20230311135415916


Solution 2: DP

Array Segmentation (Blue Bridge Cup Problem Solution)

import java.util.*;
import java.io.*;

public class Main {
    
    

    static final BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
    static final int N = 10010, MOD = (int)(1e9 + 7);
    static int[] w = new int[N];
    //表示以第i个为结尾,可以组成多段连续自然数的个数
    static int[] f = new int[N];
    static int n;

    public static void main(String[] args) throws Exception{
    
    
        n = Integer.parseInt(cin.readLine());
        String[] ss = cin.readLine().split(" ");
        for (int i = 1; i <= n; i ++) {
    
    
            w[i] = Integer.parseInt(ss[i - 1]);
        }
        //初始化
        f[0] = 0;
        for (int i = 1; i <= n; i ++) {
    
    
          //设置最大值,最小值
          int max = 0, min = Integer.MAX_VALUE;
          //不断的进行缩减范围 [j, j-1]、[j, j-2]、[j, j-3]作为最后一段区间
          //筛选[j, j-1]、[j, j-2]、[j, j-3]区间符合条件的情况,接着去叠加之前f[j - 1]已经计算好的数量
          for (int j = i; j > 0; j --) {
    
    
            max = Math.max(w[j], max);
            min = Math.min(w[j], min);
            if (max - min == i - j) f[i] = (f[i] + f[j - 1]) % MOD;
          }
        }
        System.out.println(f[n]);
    }
}

image-20230312111225237


Question H: Memory Maze (20 points)

Up, down, left, right: udrl

uuuullllddddrrrrru

#Examination Question I: Traffic lights (25 points)

Determine the train of thought: Greedy

topic

Blue Bridge Cup official solution-traffic lights

answer

dp

The global optimal solution must be related to the local optimal solution.


Question J: Pull the box (25 points)

Guess: enumeration + DP

topic

answer

Guess you like

Origin blog.csdn.net/cl939974883/article/details/129478634