早上好啊大伙,这一期依旧是蓝桥杯备赛刷题的记录。
本期题单:挑苹果、瞬移

前言
前段时间准备省赛,运气好进国赛了。所以就开始准备6月份的国赛。但是近期还有别的比赛要准备,所以刷题的速度比较慢,可能每一期就会有一两道题目。
如果大伙再刷哪道题的时候遇到问题了,也可以留言或者私信,小白兔会去先尝试一下那到题目。
挑苹果
题目
题目链接:挑苹果

思路分析
首先这道题所提到的操作其实还挺多的,咱们可以从这个方面来入手:
- 有一个 x ,ai可以通过它来改变。
- 要对 k 进行取模操作。
- 余数在 t 以内的数需要进行统计。
根据这三条规则我们可以对题目进行一些含义上的简化。
首先,是对余数的判断,根据余数一个性质,我们可以先进行取余的操作,那么我们就得到了一个存储余数的一个列表。
然后,结合第一条和第三条规则,我们就可以得到的就是 —— 获取列表中数值 [a, a + t] 的所有数,因为可以增加 x ,那么对于取余之后的数,那就只是在进行循环。
这里以题目中的数据为例来给大伙举个栗子,就很容易明白。
只看 a = 8,k = 5, t = 1
| 原数据(a) | 增加的值(x) | 取余后值 (%k) |
|---|---|---|
| 8 | 0 | 3 |
| 8 | 1 | 4 |
| 8 | 2 | 0 |
| 8 | 3 | 1 |
| 8 | 4 | 2 |
| 8 | 5 | 3 |
| 8 | 6 | 4 |
所以其实就是在这边循环,那么这个操作可以转换成在排序后的余数的列表中找到数值差为 1 的 最多的数量。
那么按照这样子解析之后,我们需要一个 %k 的余数列表,并对它进行排序。
然后就是最后答案的一个求取。这里有两个思路 ——
-
用查找算法,遍历列表,对每次遍历找到 (a)的最左边的下标 和 (a + t)最右边的下标,然后差值就是答案,求最大值就可以了。
-
用前缀和,创建所有余数的数量的列表,然后构建前缀和列表,然后求出每 t 个数的和最大的值。
大伙可以按照上面的思路尝试一下,然后再看下面的代码,代码是按照第一种方式实现的。
代码
import os
import sys
from bisect import bisect_left, bisect_right # 导入二分查找函数
# 读取输入数据:n为数组长度,k为模数,t为目标值
n, k, t = map(int, input().split())
lst_a = list(map(int, input().split())) # 读取数组元素
dp = [] # 用于存储每个元素对k取模后的结果
ans = 0 # 初始化最大连续子数组长度
# 计算每个元素对k取模的结果,并存储到dp列表中
for i in lst_a:
x = i % k
dp.append(x)
dp.sort() # 对取模后的数组进行排序,便于后续二分查找
# 遍历排序后的每个元素,寻找满足条件的最大连续子数组
for i in dp:
index1 = bisect_left(dp, i) # 找到第一个等于i的元素的索引
# 找到最后一个小于等于(i + t) % k的元素的索引
index2 = bisect_right(dp, (i + t) % k) - 1
# 计算连续子数组的长度
if index1 < index2:
ans = max(ans, index2 - index1 + 1) # 情况1:子数组在当前索引范围内
else:
# 情况2:子数组跨越了数组的首尾,需要分段计算长度
ans = max(ans, len(dp) - index1 + index2 + 1)
print(ans) # 输出满足条件的最大连续子数组长度
瞬移
题目
题目链接:瞬移

思路分析
这题的思路其实是挺清晰的,就是用 BFS,遍历所有情况,找到是否能走出到,不能就输出 -1。
但是,大家会发现,按照普通的 BFS 写,它还是会超时,问题在哪呢?
我们会发现不同的步子大小,可能会在不同时候达到同一个位置,那么这里就会重复计算,我们可以去排除这些情况,也就是 dp ,记录路径。
然后还有什么优化的地方,我们可以做一些前置计算,也就是把所有 i + j 都记录下来,然后排除掉重复的步子大小 —— 可以用 set 来存储。
大伙可以尝试一下。然后具体代码,大伙可以看下面。
代码
from collections import deque
# 读取输入:n为可选数字的数量,l为目标位置
n, l = map(int, input().split())
lst = list(map(int, input().split()))
# 预处理所有可能的移动距离d,并对l取模后去重
d_set = set()
for i in lst:
for j in lst:
d = i + j # 每次移动可选两个数的和
d_set.add(d % l) # 对l取模并去重
# BFS初始化:队列存储(当前位置, 已走步数)
queue = deque()
visited = [False] * (l + 10) # 记录已经访问过的位置,避免重复计算
queue.append((1, 0)) # 初始坐标为1,步数为0
visited[1] = True # 标记初始位置为已访问
ans = -1 # 初始化答案为-1,表示无法到达目标位置
# BFS主循环
while queue:
curr_pos, steps = queue.popleft() # 取出当前位置和步数
# 尝试所有可能的移动距离
for d in d_set:
# 计算下一个位置:(当前位置 + 移动距离 - 1) % l + 1
next_pos = (curr_pos + d - 1) % l + 1
# 如果到达目标位置l,记录步数并终止搜索
if next_pos == l:
ans = steps + 1
queue = deque() # 清空队列提前结束
break
# 如果下一个位置未被访问过,加入队列继续搜索
if visited[next_pos] == False:
visited[next_pos] = True
queue.append((next_pos, steps + 1))
print(ans) # 输出最小步数或-1


904

被折叠的 条评论
为什么被折叠?



