第十三届蓝桥杯Java研究生组部分题解

文章提供了几道编程题目,包括T1的质因数个数计算,采用从2开始遍历并分解质因数的方法;T2数位排序,通过自定义比较器实现数字的排序;T3蜂巢问题,解决两点间的最短路径,但暴力搜索导致超时;T4重新排序,讨论了优化查询顺序以最大化结果的策略,但未完全解决问题;T5重新排序的正确解决方案,利用贪心策略优化排序。
摘要由CSDN通过智能技术生成
T1 质因数个数

思路:分解质因数,从2开始遍历,遇到一个质因数就cnt ++,然后将n中的这个质因数除干净,最后的n如果大于1,就说明这个数本身是质数或者有一个大于sqrt(n)的质因数,需要最后再加一。

注意:需要开成long类型

import java.util.*;
public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		long n = sc.nextLong();
		int cnt = 0;
		for (long i = 2; i <= n / i; i ++) {
			if (n % i == 0) {
				while (n % i == 0) {
					n /= i;
				}
				cnt ++;
			}
		}
		if (n > 1) cnt ++;
		System.out.print(cnt);
	}
}
T2 数位排序

思路:重写小于号或者使用快排

  • 方式1:有一个数据超内存(96分)
import java.util.*;
public class Main {
	static class Num implements Comparable<Num>{
		public int x;
		public Num(int x) {
			this.x = x;
		}
		@Override
		public int compareTo(Num p) {
			String s1 = x + "";
			String s2 = p.x + "";
			int sum1 = 0, sum2 = 0;
			for (int i = 0; i < s1.length(); i ++) {
				sum1 += s1.charAt(i) - '0';
			}
			for (int i = 0; i < s2.length(); i ++) {
				sum2 += s2.charAt(i)- '0';
			}
			if (sum1 != sum2) return sum1 - sum2;
			return x - p.x;
		}
	}
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt(), m = sc.nextInt();
		Num[] a = new Num[n];
		for (int i = 0; i < n; i ++) {
			a[i] = new Num(i + 1);
		}
		Arrays.sort(a);
		System.out.print(a[m - 1].x);
	}
}
  • 方式2(100分)
import java.util.*;
public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt(), m = sc.nextInt();
		Integer[] a = new Integer[n];
		for (int i = 0; i < n; i ++) a[i] = i + 1;
		Arrays.sort(a, new Comparator<Integer>() {
			@Override
			public int compare(Integer a, Integer b) {
				String s1 = a + "";
				String s2 = b + "";
				int sum1 = 0, sum2 = 0;
				for (int i = 0; i < s1.length(); i ++) {
					sum1 += s1.charAt(i) - '0';
				}
				for (int i = 0; i < s2.length(); i ++) {
					sum2 += s2.charAt(i)- '0';
				}
				if (sum1 != sum2) return sum1 - sum2;
				return a - b;
			}
		});
		System.out.print(a[m - 1]);
	}
}
T3 蜂巢

错误做法(暴力宽搜TLE 2分):

import java.util.*;
public class Main {
	static class Point {
		public double x, y;
		public Point(double x, double y) {
			this.x = x;
			this.y = y;
		}
	}
	//偏移量
	static double[] dx = {-1, -0.5, 0.5, 1, 0.5, -0.5}, dy = {0, 0.5, 0.5, 0, -0.5, -0.5};
	static HashMap<Point, Integer> map = new HashMap<>();
	public static int bfs(Point start, Point end) {
		LinkedList<Point> queue = new LinkedList<Point>();
		queue.add(start);
		map.put(start, 0);
		while (!queue.isEmpty()) {
			Point t = queue.remove();
			double x = t.x, y = t.y;
			int dist = map.get(t);
			for (int i = 0; i < 6; i ++) {
				double a = x + dx[i], b = y + dy[i];
				Point p = new Point(a, b);
				if (map.containsKey(p)) continue;
				if (a == end.x && b == end.y) {
					return dist + 1;
				}
				queue.add(p);
				map.put(p, dist + 1);
			}
		}
		return -1;
	}
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int d1 = sc.nextInt(), p1 = sc.nextInt(), q1 = sc.nextInt();
		int d2 = sc.nextInt(), p2 = sc.nextInt(), q2 = sc.nextInt();
		//将相对坐标转换为笛卡尔坐标
		double x1 = dx[d1] * p1 + dx[(d1 + 2) % 6] * q1;
		double y1 = dy[d1] * p1 + dy[(d1 + 2) % 6] * q1;
		double x2 = dx[d2] * p2 + dx[(d2 + 2) % 6] * q2;
		double y2 = dy[d2] * p2 + dy[(d2 + 2) % 6] * q2;
		Point start = new Point(x1, y1);
		Point end = new Point(x2,  y2);
		System.out.print(bfs(start, end));
	}
}

大佬的优质题解

T5 重新排序

思路:多次询问,每次询问可能会有重复区间,利用差分操作,求出每个下标被查询的次数,将原素组最大的数放在查询次数最多的下标处,则再次查询结果最大

没有ac,可能有情况没考虑到(52分)

  • 错误代码仅供参考:
import java.io.*;
import java.util.*;
public class Main {
	static final int N = 100010;
	static int[] a = new int[N]; // 差分数组,记录每个下标被查询的次数
	static long[] sum1 = new long[N]; //前缀和
	static long[] sum2 = new long[N]; //前缀和
	static int[][] query = new int[N][2]; //记录查询
	public static void insert(int l, int r, int c) {
		a[l] += c;
		a[r + 1] -= c;
	}
	static class Times implements Comparable<Times>{
		public int times, index;
		public Times(int times, int index) {
			this.times = times;
			this.index = index;
		}
		@Override
		public int compareTo(Times p) {
			return this.times - p.times;
		}
	}
	public static void main(String[] args) throws IOException{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		int n = Integer.parseInt(br.readLine().split(" ")[0]);
		int[] s = new int[n]; //原数组
		int[] new_s = new int[n]; //按照频率排序后的数组
		String[] s1 = br.readLine().split(" ");
		for (int i = 0; i < n; i ++) {
			s[i] = Integer.parseInt(s1[i]);
			if (i == 0) sum1[i] = s[i];//下标从0开始,无奈之举
			else sum1[i] = sum1[i - 1] + s[i];
		}
		int q = Integer.parseInt(br.readLine().split(" ")[0]);
		int res1 = 0;
		int k1 = 0;
		for (int i = 0; i < q; i ++){
			String[] s2 = br.readLine().split(" ");
			int l = Integer.parseInt(s2[0]) - 1;
			int r = Integer.parseInt(s2[1]) - 1;
			insert(l, r, 1);
			if (l == 0) res1 += sum1[r];
			else res1 += (sum1[r] - sum1[l - 1]); //原始查询结果
			query[k1][0] = l;
			query[k1][1] = r;
			k1 ++;
		}
		//计算查询频率
		for (int i = 1; i < n; i ++) {
			if (i > 0) a[i] += a[i - 1];
		}
		Arrays.sort(s); //将原始数组从小到大排序
		Times[] times = new Times[n];
		for (int i = 0; i < n; i ++) {
			times[i] = new Times(a[i], i);
		}
		Arrays.sort(times); //将查询频率带着下标排序
		int k = 0;
		//按照查询频率将原数组排序,查询最多的下标存放数组中的最大值
		for (Times t : times) {
			new_s[t.index] = s[k ++];
		}
		//求按照查询频率排序后数组的前缀和
		for (int i = 0; i < n; i ++) {
			if (i == 0) sum2[i] = new_s[i];
			else sum2[i] += sum2[i - 1] + new_s[i];
		}
		//重新查询
		int res2 = 0;
		for (int i = 0; i < q; i ++) {
			int l = query[i][0], r = query[i][1];
			if (l == 0) res2 += sum2[r];
			else res2 += (sum2[r] - sum2[l - 1]);
		}
		System.out.print(res2 - res1);
	}
}

注:数组可以都开在main方法外,Arrasys.sort可以指定范围排序(get到的新知识点)

正规做法:统计每个位置被查询的次数同上,然后利用贪心:排序不等式,将查询次数数组升序排列,将原数组升序排列,两数组对应下标的数相乘再相加即可。查询的时候可以不用前缀和

  • ac代码:
import java.io.*;
import java.util.*;

public class Main {
    static int N = 100010;
    static int[] a = new int[N];
    static long[] s = new long[N];
    static long[] g = new long[N];
    static int n;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        n = Integer.parseInt(br.readLine().split(" ")[0]);
        String[] v = br.readLine().split(" ");
        for (int i = 1; i <= n; i ++) {
            a[i] = Integer.parseInt(v[i - 1]);
            s[i] = s[i-1] + a[i];
        }
        int m = Integer.parseInt(br.readLine());
        long res1 = 0;
        for (int i = 0; i < m; i++) {
            v = br.readLine().split(" ");
            int l = Integer.parseInt(v[0]);
            int r = Integer.parseInt(v[1]);
            g[l] ++;
            g[r + 1] --;
            res1 += s[r] - s[l - 1];
        }
        for (int i = 1; i <= n; i++) {
            g[i] += g[i - 1];
        }
        long res2 = 0;
        Arrays.sort(a);
        Arrays.sort(g);
        int pre = g.length - 1;
        while (g[pre] != 0){
            res2 += g[pre] * a[pre];
            pre --;
        }
        System.out.println(res2 - res1);
    }
}
T6 技能升级: 直接模拟暴力,得40%的分
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

辞寒oo

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

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

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

打赏作者

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

抵扣说明:

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

余额充值