蓝桥杯 第 1 场算法双周赛 解题报告

2024-03-18 13:30

本文主要是介绍蓝桥杯 第 1 场算法双周赛 解题报告,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言


整体评价

这是蓝桥云课的第一场公开周赛,还是挺用心的。因为第一场比赛,整体比赛难度还是有所放低。


A. 三带一

Q: 四张手牌,是否能构成3带1的牌型

签到题, 有多种思路

  • 最小表示式

        排序后,一定呈现 AAAB, 或者 ABBB 型的牌,注意 A != B

  • 计数统计

        一定存在计数为3和计数为1的key,注意只有4张牌

import java.io.*;
import java.util.*;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(new BufferedInputStream(System.in));int t = sc.nextInt();while (t-- > 0) {char[] str = sc.next().toCharArray();Map<Integer, Integer> hash = new HashMap<>();for (char c: str) {hash.merge((int)c, 1, Integer::sum);}// 同时包含计数1和计数3,只有4张牌,则一定是3带1boolean res = hash.values().contains(1) && hash.values().contains(3);System.out.println(res ? "Yes" : "No");}}}

B. 数树数

Q: 满二叉树,根据指令左右向下,求最后的节点代表的数值

找规律的题,其实可以手玩一下,就能发现其中的窍门

其实用数组构建的堆,线段树等,都有类似的规律,父节点和子节点之间,其索引值倍增,偏差1

这题的规律为

向左,a_{i+1}=2 * a_i - 1

向右 a_{i+1}=2 * a_i

自顶向下模拟即可

import java.io.BufferedInputStream;
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(new BufferedInputStream(System.in));int n = sc.nextInt();int q = sc.nextInt();for (int i = 0; i < q; i++) {char[] cmd = sc.next().toCharArray();long res = 1;for (char c: cmd) {if (c == 'L') {res = 2 * res - 1;} else {res = 2 * res;}}System.out.println(res);}}}

C. 分组

Q: 就是把一个数组分成k组,使得最大的一组高度差最小。

这种最大最小的问题,往往是二分的解法,一般百试不爽,^_^

可以先排序,然后在尝试分组

二分容易,但是核心的check逻辑,该如何组织呢?

假定一个高度差h,然后从左到右贪心,使得每一组成员越多越好,如果最终的组数g<=k, 说明这个高度差满足需求,反之则不行。

import java.io.BufferedInputStream;
import java.util.Arrays;
import java.util.Scanner;public class Main {static boolean check(int[] arr, int m, int k) {int i = 0;int tk = 0;while (i < arr.length) {int j = i + 1;tk++;while (j < arr.length && arr[j] - arr[i] <= m) {j++;}i = j;}return tk <= k;}public static void main(String[] args) {Scanner sc = new Scanner(new BufferedInputStream(System.in));int n = sc.nextInt(), k = sc.nextInt();int[] arr = new int[n];for (int i = 0; i < n; i++) {arr[i] = sc.nextInt();}Arrays.sort(arr);int l = 0, r = arr[n - 1] - arr[0];while (l <= r) {int m = l + (r - l) / 2;if (check(arr, m, k)) {r = m - 1;} else {l = m + 1;}}System.out.println(l);}}

D. 健身

Q: 就是在几个离散的时间区间内,安排一些健身活动(某种健身活动无限续杯),需要完整,求最大的收益和。

健身活动(无数量限制),因此每个区间的最优解彼此独立,互不影响,而且总和就是最大的收益和。

那一个区间,如何求解呢?

本质还是一个

有容量上限的完全背包问题

所以这题的思路是

  • 拆解离散的可用时间片段
  • 完全背包(跑一次就行)
import java.io.*;
import java.util.*;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(new BufferedInputStream(System.in));int n = sc.nextInt(), m = sc.nextInt(), x = sc.nextInt();int[][] ws = new int[m][2];List<Integer> arr = new ArrayList<>();for (int i = 0; i < x; i++) {int b = sc.nextInt();arr.add(b);}for (int i= 0; i < m; i++) {ws[i][0] = sc.nextInt();ws[i][1] = sc.nextInt();}// 抽取离散的空闲时间段Collections.sort(arr);List<Integer> empty = new ArrayList<>();for (int i = 0; i < arr.size() - 1; i++) {int v = arr.get(i + 1) - arr.get(i) - 1;if (v > 0) empty.add(v);}// 注意头尾if (arr.size() > 0) {if (arr.get(0) > 1) empty.add(arr.get(0) - 1);if (arr.get(arr.size() - 1) < n) empty.add(n - arr.get(arr.size() - 1));}// 完全背包long[] dp = new long[n + 1];for (int i = 0; i < m; i++) {int s = 1 << ws[i][0];for (int j = 0; j + s <= n; j++) {dp[j + s] = Math.max(dp[j + s], dp[j] + ws[i][1]);}}// 再来一个前缀预处理for (int i = 1; i <= n; i++) {dp[i] = Math.max(dp[i], dp[i - 1]);}long sum = 0;for (int e: empty) {sum += dp[e];}System.out.println(sum);}}


E. 契合匹配

Q: 求两个字符串,通过移动,是否可以匹配(相等)

当然这边的匹配,是大写字母匹配小写字母,稍微饶了一下。

这是道很典的字符串板子题

  • KMP
  • Z函数
  • 字符串Hash

这些方法都可以,而且都是O(n)的,不过这里可向左,也可以向右,所以这边需要特别注意下。

这边使用了字符串hash,而且这题单hash可以过,^_^.

import java.io.BufferedInputStream;
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(new BufferedInputStream(System.in));int n = sc.nextInt();char[] str1 = sc.next().toCharArray();char[] str2 = sc.next().toCharArray();for (int i = 0; i < n; i++) {if (str2[i] >= 'a' && str2[i] <= 'z') {str2[i] = (char)(str2[i] - 'a' + 'A');} else {str2[i] = (char)(str2[i] - 'A' + 'a');}}long mod = (long)1e9 + 7;StringHash hash1 = new StringHash(new String(str1), 13, mod);StringHash hash2 = new StringHash(new String(str2), 13, mod);int inf = Integer.MAX_VALUE / 10;int ans = inf;long h1 = hash1.query(0, n - 1);if (h1 == hash2.query(0, n - 1)) {ans = 0;} else {for (int i = 0; i < n - 1; i++) {long h2 = hash2.rotate(i);if (h1 == h2) {ans = Math.min(ans, Math.min((i + 1), n - (i + 1)));}}}if (ans == inf) {System.out.println("No");} else {System.out.println("Yes");System.out.println(ans);}}static class StringHash {char[] str;long p, mod;int n;long[] pre; // hash前缀和long[] pow; // p的幂次public StringHash(String s, int p, long mod) {this.str = s.toCharArray();this.p = p;this.mod = mod;this.n = str.length;pre = new long[n + 1];pow = new long[n + 1];pow[0] = 1;for (int i = 1; i <= n; i++) {pow[i] = pow[i - 1] * p % mod;}for (int i = 0; i < str.length; i++) {pre[i + 1] = (pre[i] * p % mod + str[i]) % mod;}}long query(int l, int r) {long res = pre[r + 1] - pre[l] * pow[r - l + 1] % mod;return (res % mod + mod) % mod;}long rotate(int l) {if (l < 0 || l >= str.length - 1) {return query(0, str.length - 1);} else {long h1 = query(0, l);long h2 = query(l + 1, str.length - 1);return (h2 * pow[l + 1] % mod + h1) % mod;}}static long evaluate(String s, int p, long mod) {long h = 0;for (char c: s.toCharArray()) {h = (h * p % mod + c) % mod;}return h;}}}


F. 奇怪的线段

Q: 给定一些区间集合,查询a, b两点,其a在区间,b不在。求集合中,有多少区间符合条件?

区间的问题,可以往二维偏序的解法靠拢

因为查询很多,可以借助离线解法,把查询和被查询区间整合到一起。

这边提供一个离线解法,构建操作序列,并借助树状数组来统计

假设a < b

对于查询(a, b),构建元组

(1, a, b, i), type=1,表示查询

对于区间(x, y), 则构建两个元组

(0, x, y, _), type=0,表示添加区间

(2, y, _, _), type=2, 表示删除区间

按左端点作为一级排序,按操作类型作为二级排序

然后引入树状数组(需要离散化映射),维护右端点的计数

这样天然保证了包含a点,而不包含b点,用树状数组范围查询一下即可。

而对于a > b的情况

需要从右端点的切入并排序

注:这个解法,码量还是有点大,而且必须加快读。更好的解法,见官解:差分+容斥原理

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
import java.util.stream.Collectors;public class Main {static void handle1(int[][] intervals, int[][] queries, int[] res) {Set<Integer> range = new TreeSet<>();int n = intervals.length;List<int[]> ops = new ArrayList<>();for (int i = 0; i < n; i++) {ops.add(new int[] {intervals[i][0], intervals[i][1], 0, i});ops.add(new int[] {intervals[i][1], -1, 2, i});range.add(intervals[i][1]);}// 离线, 在线int q = queries.length;for (int i = 0; i < q; i++) {if (queries[i][0] < queries[i][1]) {ops.add(new int[]{queries[i][0], queries[i][1], 1, i});range.add(queries[i][1]);}}int ptr = 0;Map<Integer, Integer> idMap = new HashMap<>();for (int k: range) {idMap.put(k, ++ptr);}int m = idMap.size();BIT bit = new BIT(m);Collections.sort(ops, Comparator.comparing((int[] x) -> x[0]).thenComparingInt(x -> x[2]));for (int[] e: ops) {int p = e[2];if (p == 0) {bit.update(idMap.get(e[1]), 1);} else if (p == 1) {int cnt = bit.query(idMap.get(e[1]) - 1);res[e[3]] = cnt;} else {bit.update(idMap.get(e[0]), -1);}}}static void handle2(int[][] intervals, int[][] queries, int[] res) {Set<Integer> range = new TreeSet<>();int n = intervals.length;List<int[]> ops = new ArrayList<>();for (int i = 0; i < n; i++) {ops.add(new int[] {intervals[i][1], intervals[i][0], 0, i});ops.add(new int[] {intervals[i][0], -1, 2, i});range.add(intervals[i][0]);}// 离线, 在线int q = queries.length;for (int i = 0; i < q; i++) {if (queries[i][0] > queries[i][1]) {ops.add(new int[]{queries[i][0], queries[i][1], 1, i});range.add(queries[i][1]);}}int ptr = 0;Map<Integer, Integer> idMap = new HashMap<>();for (int k: range) {idMap.put(k, ++ptr);}int m = idMap.size();BIT bit = new BIT(m);Collections.sort(ops, Comparator.comparing((int[] x) -> -x[0]).thenComparingInt(x -> x[2]));for (int[] e: ops) {int p = e[2];if (p == 0) {bit.update(idMap.get(e[1]), 1);} else if (p == 1) {int cnt = bit.query(m) - bit.query(idMap.get(e[1]));res[e[3]] = cnt;} else {bit.update(idMap.get(e[0]), -1);}}}public static void main(String[] args) {AReader sc = new AReader();int n = sc.nextInt(), q= sc.nextInt();int[][] intervals = new int[n][2];for (int i = 0; i < n; i++) {intervals[i][0] = sc.nextInt();intervals[i][1] = sc.nextInt();}// 离线, 在线int[][] queries = new int[q][2];for (int i = 0; i < q; i++) {queries[i][0] = sc.nextInt();queries[i][1] = sc.nextInt();}// 离散化 + 离线计算int[] res = new int[q];handle1(intervals, queries, res);handle2(intervals, queries, res);System.out.println(Arrays.stream(res).mapToObj(String::valueOf).collect(Collectors.joining("\n")));}static class BIT {int n;int[] arr;public BIT(int n) {this.n = n;this.arr = new int[n + 1];}void update(int p, int d) {while (p <= n) {this.arr[p] += d;p += p & -p;}}int query(int p) {int r = 0;while (p > 0) {r += arr[p];p -= p&-p;}return r;}}staticclass AReader {private BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));private StringTokenizer tokenizer = new StringTokenizer("");private String innerNextLine() {try {return reader.readLine();} catch (IOException ex) {return null;}}public boolean hasNext() {while (!tokenizer.hasMoreTokens()) {String nextLine = innerNextLine();if (nextLine == null) {return false;}tokenizer = new StringTokenizer(nextLine);}return true;}public String nextLine() {tokenizer = new StringTokenizer("");return innerNextLine();}public String next() {hasNext();return tokenizer.nextToken();}public int nextInt() {return Integer.parseInt(next());}public long nextLong() {return Long.parseLong(next());}//        public BigInteger nextBigInt() {
//            return new BigInteger(next());
//        }// 若需要nextDouble等方法,请自行调用Double.parseDouble包装}}


写在最后

这篇关于蓝桥杯 第 1 场算法双周赛 解题报告的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/822484

相关文章

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

【专题】2024飞行汽车技术全景报告合集PDF分享(附原数据表)

原文链接: https://tecdat.cn/?p=37628 6月16日,小鹏汇天旅航者X2在北京大兴国际机场临空经济区完成首飞,这也是小鹏汇天的产品在京津冀地区进行的首次飞行。小鹏汇天方面还表示,公司准备量产,并计划今年四季度开启预售小鹏汇天分体式飞行汽车,探索分体式飞行汽车城际通勤。阅读原文,获取专题报告合集全文,解锁文末271份飞行汽车相关行业研究报告。 据悉,业内人士对飞行汽车行业

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

秋招最新大模型算法面试,熬夜都要肝完它

💥大家在面试大模型LLM这个板块的时候,不知道面试完会不会复盘、总结,做笔记的习惯,这份大模型算法岗面试八股笔记也帮助不少人拿到过offer ✨对于面试大模型算法工程师会有一定的帮助,都附有完整答案,熬夜也要看完,祝大家一臂之力 这份《大模型算法工程师面试题》已经上传CSDN,还有完整版的大模型 AI 学习资料,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

dp算法练习题【8】

不同二叉搜索树 96. 不同的二叉搜索树 给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。 示例 1: 输入:n = 3输出:5 示例 2: 输入:n = 1输出:1 class Solution {public int numTrees(int n) {int[] dp = new int

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能