2022年十三届蓝桥杯省赛JavaB组,1-8题解全通过100%,省一国二自解

目录

试题A:星期计算

试题B:山

试题C:字符统计

试题D:最少刷题数

试题E:求阶乘

试题F:最大子矩阵

试题G:数组切分

试题H:回忆迷宫


试题A:星期计算

	// 十三届省赛第一题,星期计算
	public static void f1() {
		// 不算结果取模即可,缓存无限大
		int res = (int) (Math.pow(20, 22) % 7 + 6);
		System.out.println(res);
	}

试题B:山

    // 十三届省赛第二题,山:暴力
	public static void f2() {
		long res = 0;
		for (int i = 2022; i <= 2022222022; i++) {
			if (check1(i + "")) {
				// System.out.println(i);
				res++;
			}
		}
		System.out.println(res);
	}

	public static boolean check1(String str) {
		int len = str.length();
		// 前大半不减
		for (int i = 0; i < len - len / 2 - 1; i++) {
			if (str.charAt(i) > str.charAt(i + 1)) {
				return false;
			}
		}
		// 后小半回文
		for (int i = len - len / 2; i < len; i++) {
			if (str.charAt(i) != str.charAt(len - i - 1)) {
				return false;
			}
		}
		return true;
	}
    // 方法二,优化:按位数分类,注意头尾
	public static void f3() {
		long res = 0;
		for (int i = 21; i <= 99; i++) {
			if (check2(i + "")) {
				res++;
			}
		}
		for (int i = 111; i <= 9999; i++) {
			if (check2(i + "")) {
				res += 2;
			}
		}
		for (int i = 11111; i <= 99999; i++) {
			if (check2(i + "")) {
				// System.out.println(i);
				res++;
			}
		}
		for (int i = 11111; i <= 20221; i++) {
			if (check2(i + "")) {
				res++;
			}
		}
		System.out.println(res);
	}

	public static boolean check2(String str) {
		char[] chs = str.toCharArray();
		Arrays.sort(chs);
		if (Arrays.equals(chs, str.toCharArray())) {
			return true;
		}
		return false;
	}

试题C:字符统计

    // 十三届省赛第三题,字符统计
	public static void f4(String str) {
		// Z的ascll=90
		int[] arr = new int[100];
		for (int i = 0; i < str.length(); i++) {
			arr[str.charAt(i)]++;
		}
		int max = 0;
		for (int i = 0; i < arr.length; i++) {
			if (arr[i] > max) {
				max = arr[i];
			}
		}
		for (int i = 0; i < arr.length; i++) {
			if (arr[i] == max) {
				// 顺序拿出即为有序
				System.out.print((char) i);
			}
		}
	}

试题D:最少刷题数

    // 十三届省赛第四题,最少刷题数(排序后,查找一遍,遍历计算所有结果)
	public static void f5(List<Integer> list, List<Integer> sist) {
		int num = sist.get(sist.size() / 2);
		int pre = sist.indexOf(num);
		int next = sist.size() - 1 - sist.lastIndexOf(num);
		for (int i = 0; i < list.size(); i++) {
			int temp = list.get(i);
			//大的比小的少
			if(next<pre) {
				if(temp<num) {
					System.out.print(num-temp+" ");
				}else {
					System.out.print(0+" ");
				}
			}
			//大的比小的等
			else if(next==pre) {
				if(temp<num) {
					System.out.print(num-temp+1+" ");
				}else {
					System.out.print(0+" ");
				}
			}
			//大的比小的多
			else {
				if(temp<=num) {
					System.out.print(num-temp+1+" ");
				}else {
					System.out.print(0+" ");
				}
			}
		}
	}

试题E:求阶乘

    //十三届省赛第五题,求阶乘:二分查找阶乘的值
	public static long f6(long k) {
		//先确定边界
		long l=-1,r;
		long p=1;//外拓指针
		while (f7(p)<k) {
			l=p;
			p*=2;
		}
		r=p;
		//再套模板(找到第一个满足条件的r)
		while (l+1!=r) {
			long m=(l+r)/2;
			if(f7(m)>=k) {
				r=m;
			}else {
				l=m;
			}
		}
		if(f7(r)==k) {
			return r;
		}else {
			//处理没有的情况,如k=5
			return -1;
		}
	}
	
	//欧几里得找5的因子即为0的个数(处理没有的情况,如sum=5)
	public static long f7(long m) {
		long n=m;
		long sum=0;
		//欧几里得公式
		while (n>0) {
			sum+=n/5;
			n/=5;
		}
		return sum;
	}

试题F:最大子矩阵

	// 具有列最大最小值的变形一维数组变形一维求最大子数组(优化:sum预算+跳列遍历)
	public static int f3(int lim, int[][] arr) {
		int sum = 0;// 变形子数组的最大元素个数(0表示单列不满足)
		flag: for (int i = 0; i < arr[0].length; i++) {
			int smin = arr[0][i], smax = arr[1][i];
			if (smax - smin <= lim) {
				sum = Math.max(1, sum);
			} else {
				continue flag;
			}
			int sminy = i, smaxy = i;// 记录左极端值的列
			for (int j = i + 1; j < arr[0].length; j++) {
//				System.out.println(i+"  "+j);
				if (arr[1][j] > smax) {
					if (arr[1][j] - smin > lim) {
						i = Math.min(sminy, smaxy);// 跳列遍历
						continue flag;
					}
					smax = arr[1][j];
					smaxy = j;
				}
				if (arr[0][j] < smin) {
					if (smax - arr[0][j] > lim) {
						i = Math.min(sminy, smaxy);// 跳列遍历
						continue flag;
					}
					smin = arr[0][j];
					sminy = j;
				}
				if (j - i + 1 > sum) {// 此子数组的元素个数
					sum = j - i + 1;
				}
				if (sum >= arr[0].length - i) {// 预算此子数组最大个数,是否还需要遍历
					break flag;
				}
			}
		}
		return sum;
	}

	// 十三届省赛第六题,最大子矩阵:二维化一维(枚举行组合)
	public static int f4(int lim, int[][] table) {
		int sum = 1;
		int[][] arr = new int[2][table[0].length];// 具有列最大最小值的变形一维数组
		for (int i = 0; i < table.length; i++) {
			for (int j = i; j < table.length; j++) {
				for (int k = 0; k < arr[0].length; k++) {// 组合为具有列最大最小值的变形一维数组
					arr[0][k] = table[i][k];// 初始化
					arr[1][k] = table[i][k];// 初始化
					for (int t = i; t <= j; t++) {
						arr[0][k] = Math.min(table[t][k], arr[0][k]);
						arr[1][k] = Math.max(table[t][k], arr[1][k]);
					}
				}
				int mid = f3(lim, arr);
//				System.out.println(Arrays.toString(arr[0]));
//				System.out.println(Arrays.toString(arr[1]));
//				System.out.println(mid);
				sum = Math.max(mid * (j - i + 1), sum);
				Arrays.fill(arr[0], 0);// 清除
				Arrays.fill(arr[1], 0);// 清除
			}
		}
		return sum;
	}

试题G:数组切分

//	//十三届省赛第七题,数组切分:动规递推
//	2 1 5 4 3
//	2        :arr[0]=1                       =1
//	2 1      :arr[1]=arr[0]+1                =2
//	2 1 5    :arr[2]=arr[1]+0+0              =2
//	2 1 5 4  :arr[3]=arr[2]+arr[1]+0+0       =4
//	2 1 5 4 3:arr[4]=arr[3]+arr[2]+arr[1]+0+1=9
	public static long f5(int[] arr) {
		long[] dp = new long[arr.length];
		dp[0] = 1;// 初始化第一个
		for (int i = 1; i < dp.length; i++) {
			int min = arr[i], max = arr[i];// 初始化
			for (int j = i; j >= 0; j--) {// 后往前求dp[i]
				min = Math.min(min, arr[j]);// 维持最小值
				max = Math.max(max, arr[j]);// 维持最大值
				if (j != 0) {
					if (max - min == i - j) {// 核心:最大减最小等于长度则为连续如:(2 1 3:3-1=2-0)
						dp[i] += dp[j - 1] % 1000000007;// 处理MOD
					}
				} else {// 判断整体是否满足
					if (max - min == i - j) {// 核心:最大减最小等于长度则为连续如:(2 1 3:3-1=2-0)
						dp[i] += 1;
					}
				}
			}
		}
//		System.out.println(Arrays.toString(dp));
		return dp[arr.length - 1] % 1000000007;// 最后再处理MOD
	}

试题H:回忆迷宫

	// 十三届省赛第八题,回忆迷宫:先填墙(路边+内空)再挖路
	static Character[][] table = new Character[300][300];// 取150,150为中心开始
	public static void f7(char[] arr) {
		int nx = 150, ny = 150, mx = 150, my = 150;// 最小最大的坐标,输出用
		for (Character[] cs : table) {
			Arrays.fill(cs, ' ');// 初始化
		}
		int[][] empty = new int[2][arr.length + 1];
		int x = 150, y = 150;// 初始化位坐标
		empty[0][0] = 150;// 初始化路的x坐标
		empty[1][0] = 150;// 初始化路的y坐标

		// 填墙
		table[x - 1][y] = '*';// 初始化坐标墙
		table[x + 1][y] = '*';// 初始化坐标墙
		table[x][y - 1] = '*';// 初始化坐标墙
		table[x][y + 1] = '*';// 初始化坐标墙
		for (int i = 0; i < arr.length; i++) {
			if (arr[i] == 'U') {// 上
				x--;
			} else if (arr[i] == 'D') {// 下
				x++;
			} else if (arr[i] == 'R') {// 右
				y++;
			} else if (arr[i] == 'L') {// 左
				y--;
			}

			empty[0][i + 1] = x;// 记录路的x坐标
			empty[1][i + 1] = y;// 记录路的y坐标

			nx = Math.min(nx, x);// 维持最小x坐标
			ny = Math.min(ny, y);// 维持最小y坐标
			mx = Math.max(mx, x);// 维持最大x坐标
			my = Math.max(my, y);// 维持最大y坐标

			table[x - 1][y] = '*';// 填墙
			table[x + 1][y] = '*';// 填墙
			table[x][y - 1] = '*';// 填墙
			table[x][y + 1] = '*';// 填墙
		}

//		for (int i = nx - 1; i <= mx + 1; i++) {
//			for (int j = ny - 1; j <= my + 1; j++) {
//				System.out.print(table[i][j]);
//			}
//			System.out.println();
//		}
//		System.out.println("==================");

		// 填满中间(dfs深搜法,全面)
		f8(nx-1,ny-1,mx+1,my+1);
		
//		for (int i = nx - 1; i <= mx + 1; i++) {
//			for (int j = ny - 1; j <= my + 1; j++) {
//				System.out.print(table[i][j]);
//			}
//			System.out.println();
//		}
//		System.out.println("==================");

		// 挖空
		for (int i = 0; i < empty[0].length; i++) {
			table[empty[0][i]][empty[1][i]] = ' ';

		}

		for (int i = nx - 1; i <= mx + 1; i++) {
			for (int j = ny - 1; j <= my + 1; j++) {
				System.out.print(table[i][j]);
			}
			System.out.println();
		}
	}
	
	//填满中间,dfs深搜
	static Character[][] copy=new Character[table.length][];
	public static void f8(int nx,int ny,int mx,int my) {//左上右下坐标
		for (int i = 0; i < copy.length; i++) {
			copy[i]=table[i].clone();//复制表格
		}
		for (int i = nx; i <= mx; i++) {
			for (int j = ny; j <= my; j++) {
				if (copy[i][j] == ' ') {// 如果是一个被包围的空格则填墙
					
					dfs(nx, ny, mx, my, i, j);
					
					//填充原表格
					if(flag) {
						for (int k = 0; k < listx.size(); k++) {
							table[listx.get(k)][listy.get(k)]='*';
						}
					}
					
					//恢复
					flag=true;
					listx.clear();
					listy.clear();
				}
			}
		}
	}
	static boolean flag=true;
	static List<Integer> listx=new ArrayList<Integer>();
	static List<Integer> listy=new ArrayList<Integer>();
	public static void dfs(int nx,int ny,int mx,int my,int x,int y) {//左上右下坐标
		copy[x][y]='*';
		listx.add(x);
		listy.add(y);
		if(x==nx||x==mx||y==ny||y==my) {
			flag=false;
		}
		if(copy[x][y+1]==' '&&y+1<=my) {
			dfs(nx, ny, mx, my, x, y+1);
		}
		if(copy[x][y-1]==' '&&y-1>=ny) {
			dfs(nx, ny, mx, my, x, y-1);
		}
		if(copy[x+1][y]==' '&&x+1<=mx) {
			dfs(nx, ny, mx, my, x+1, y);
		}
		if(copy[x-1][y]==' '&&x-1>=nx) {
			dfs(nx, ny, mx, my, x-1, y);
		}
	}

  • 22
    点赞
  • 105
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BB-X

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值