【算法】2022年第十三届蓝桥杯大赛软件类省赛Java大学B组真题

个人主页: NiKo

算法专栏:算法设计与分析


目录

题目 2672: 字符统计

题目 2673: 最少刷题数

题目 2674: 求阶乘

题目 2675: 最大子矩阵

题目 2676: 数组切分

题目 2677: 回忆迷宫

题目 2678: 红绿灯

题目 2679:拉箱子


题目 2672: 字符统计

  • 题目

  • 题解 
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        //创建扫描器
        Scanner sc = new Scanner(System.in);
        //读取字符串
        String S = sc.nextLine();
        //获取字符串长度
        int length = S.length();
        //定义一个高级计数器
        int[] counts = new int[26];
        //关闭扫描器
        sc.close();
        //通过减去'A'来保证索引为对应的字母编号(非ASCII),从而对每一个字母进行计数
        for (int i = 0; i < length; i++) {
            counts[S.charAt(i) - 'A']++;
        }
        //之后找出最大值
        int max = 0;
        //找出出现次数最多的字母的出现次数
        for (int i = 0; i < counts.length; i++) {
            //为了不改变原来数组的索引所对应的值
            int count = counts[i];
            if (count > max) {
                max = count;
            }
        }
        //输出出现次数最多的字母的索引,并转化为为字母。
        for (int i = 0; i < counts.length; i++) {
            if (counts[i] == max) {
                System.out.print((char) ('A' + i));
            }
        }
    }
}

题目 2673: 最少刷题数

  • 题目

  •  题解
import java.util.Arrays;
import java.util.Scanner;
 
public class ProblemStatistics {
 
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] arr = new int[n];
        for(int i=0 ; i<n ; i++) {
            arr[i]=sc.nextInt();
        }
        sc.close();
        
        int[] sortarr = arr.clone();    
        Arrays.sort(sortarr);
        
        int mid = sortarr[n/2];
        int more=0 , less=0;
        for(int i: arr) {
            if(i<mid) less++;
            else if(i>mid) more++;
        }
        
        int flag=0 , midflag=0;
        if(more>=less) flag=1;
        if(more>less) midflag=1;
 
        for(int i=0 ; i<n ; i++){  //遍历判断每个数是小于、等于还是大于mid
            if(arr[i]<mid){
                System.out.print(mid+flag-arr[i]);    //flag=1时是case2,3  =0时是case1
            }else if(arr[i]==mid && midflag==1){
                System.out.print(mid+midflag-arr[i]); //midflag=1时是case2  =0时是case1,3
            }else{
                System.out.print("0");
            }
            
            if(i<n-1) System.out.print(" ");
        }
    }
}

题目 2674: 求阶乘

  • 题目

  • 题解 
import java.util.Scanner;

public class Main {
	public static void main(String args[]) {
		Scanner scanner = new Scanner(System.in);
		long k = scanner.nextLong();
		long count;
		long a = 5;
		while (true) {
			long tempA = a;
			count = 0;
			while (tempA > 0) {
				tempA /= 5;
				count += tempA;
			}
			if (count < k) {
				a += 5;
			} else if (count == k) {
				System.out.println(a);
				break;
			} else {
				System.out.println(-1);
				break;
			}
		}
		scanner.close();
	}
}

题目 2675: 最大子矩阵

  • 题目

  • 题解 
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
typedef long long LL;
typedef pair<int,int>pii;
const int mod = 1e9 + 7 , INF = 0x3f3f3f3f , N = 1e5 + 10;
 
int g[100][N];
int n,m;
int limit;
struct edge1
{
    int v;
    int id;
    bool operator < (const edge1 & w)const
    {
        if (v != w.v)
            return v < w.v;
        return id > w.id;
    }
};
struct edge2
{
    int v;
    int id;
    bool operator < (const edge2 & w)const
    {
        if (v != w.v)
            return v > w.v;
        return id > w.id;
    }
};
struct Node
{
    int l,r;
    int minv;
    int maxv;
}tr[N * 4];
 
void push_up(int x)
{
    tr[x].minv = min(tr[x << 1].minv,tr[x << 1 | 1].minv);
    tr[x].maxv = max(tr[x << 1].maxv,tr[x << 1 | 1].maxv);
}
void build(int x,int l,int r)
{
    tr[x] = {l,r};
    
    if (l == r)
    {
        int w = g[(r - 1) % n + 1][(r - 1) / n + 1];
        tr[x] = {l,r,w,w};
        return;
    }
    int mid = l + r >> 1;
    build(x << 1,l,mid);
    build(x << 1 | 1,mid + 1,r);
    push_up(x);
}
 
int queryMin(int x,int l,int r)
{
    if (tr[x].l >= l && tr[x].r <= r)
        return tr[x].minv;
    int mid = tr[x].l + tr[x].r >> 1;
    
    int minv = INF;
    if (l <= mid)
        minv = queryMin(x << 1,l,r);
    if (r > mid)
        minv = min(minv,queryMin(x << 1 | 1,l,r));
    return minv;
}
 
int queryMax(int x,int l,int r)
{
    if (tr[x].l >= l && tr[x].r <= r)
        return tr[x].maxv;
    int mid = tr[x].l + tr[x].r >> 1;
    
    int maxv = -1;
    if (l <= mid)
        maxv = queryMax(x << 1,l,r);
    if (r > mid)
        maxv = max(maxv,queryMax(x << 1 | 1,l,r));
    return maxv;
}
 
void init()
{
    scanf("%d%d",&n,&m);
    for (int i = 1 ; i <= n ; i ++)
    for (int j = 1 ; j <= m ; j ++) 
        scanf("%d",&g[i][j]);
    scanf("%d",&limit);
    build(1,1,n * (m + 1));
}
 
int getMin(int i1,int j1,int i2,int j2)
{
    int a = i1 + n * (j1 - 1);
    int b = i2 + n * (j2 - 1);
    return queryMin(1,a,b);    
}
 
int getMax(int i1,int j1,int i2,int j2)
{
    int a = i1 + n * (j1 - 1);
    int b = i2 + n * (j2 - 1);
    return queryMax(1,a,b);    
}
 
int main()
{
    init();
    int res = 0;
    for (int i1 = 1 ; i1 <= n ; i1 ++)
    for (int i2 = i1 ; i2 <= n ; i2 ++)
    {
        priority_queue<edge1> q1;
        priority_queue<edge2> q2;
        for (int l = 1,r = 1; r <= m ; r ++)
        {
            int maxv = getMax(i1,r,i2,r);
            int minv = getMin(i1,r,i2,r);
            if (maxv - minv > limit)
            {
                while (q1.size())
                    q1.pop();
                while (q2.size())
                    q2.pop();
                l = r + 1;
                continue;
            }
            while (q1.size() && q1.top().v <= maxv)
                q1.pop();
            q1.push({maxv,r});
            while (q2.size() && q2.top().v >= minv)
                q2.pop();
            q2.push({minv,r});
            
            while (q1.top().v - q2.top().v > limit)
            {
                l ++;
                while (q1.size() && q1.top().id < l)
                    q1.pop();
                while (q2.size() && q2.top().id < l)
                    q2.pop();
            }
            res = max(res,(i2 - i1 + 1) * (r - l + 1));
        }
        
    }
    
    printf("%d",res);
    
    return 0;
}

题目 2676: 数组切分

  • 题目

  • 题解 
	// 具有列最大最小值的变形一维数组变形一维求最大子数组(优化: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;
	}

题目 2677: 回忆迷宫

  • 题目

  •  题解
	// 十三届省赛第八题,回忆迷宫:先填墙(路边+内空)再挖路
	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);
		}
	}

题目 2678: 红绿灯

  • 题目


题目 2679:拉箱子

  • 题目

评论 38
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

NiKo_sx

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

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

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

打赏作者

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

抵扣说明:

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

余额充值