第十五届蓝桥杯大赛软件赛国赛Python 大学 C 组试做【本期题单: 挑苹果、瞬移】

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

前言

前段时间准备省赛,运气好进国赛了。所以就开始准备6月份的国赛。但是近期还有别的比赛要准备,所以刷题的速度比较慢,可能每一期就会有一两道题目。

如果大伙再刷哪道题的时候遇到问题了,也可以留言或者私信,小白兔会去先尝试一下那到题目。

文章目录

    • 前言
  • 挑苹果
    • 题目
    • 思路分析
    • 代码
  • 瞬移
    • 题目
    • 思路分析
    • 代码
  • 感谢大伙观看,别忘了三连支持一下
  • 大家也可以关注一下我的其它专栏,同样精彩喔~
  • 大伙也可以添加下面微信来和我交流

挑苹果

题目

题目链接:挑苹果
第十五届蓝桥杯大赛软件赛国赛Python 大学 C 组试做【本期题单: 挑苹果、瞬移】_第1张图片

思路分析

首先这道题所提到的操作其实还挺多的,咱们可以从这个方面来入手:

  1. 有一个 x ,ai可以通过它来改变。
  2. 要对 k 进行取模操作。
  3. 余数在 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 的余数列表,并对它进行排序。

然后就是最后答案的一个求取。这里有两个思路 ——

  1. 用查找算法,遍历列表,对每次遍历找到 (a)的最左边的下标 和 (a + t)最右边的下标,然后差值就是答案,求最大值就可以了。

  2. 用前缀和,创建所有余数的数量的列表,然后构建前缀和列表,然后求出每 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)  # 输出满足条件的最大连续子数组长度

瞬移

题目

题目链接:瞬移
第十五届蓝桥杯大赛软件赛国赛Python 大学 C 组试做【本期题单: 挑苹果、瞬移】_第2张图片

思路分析

这题的思路其实是挺清晰的,就是用 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

感谢大伙观看,别忘了三连支持一下

大家也可以关注一下我的其它专栏,同样精彩喔~

大伙也可以添加下面微信来和我交流

你可能感兴趣的:(蓝桥杯比赛备赛指南,蓝桥杯,python,c语言)