第十三届蓝桥杯 python B组 第二场 题目及其解析

试题A:

# 签到题,不过不知道是不是的

print("ABC")

试题B:

思路:本题看起来不像有特殊解法的样子...所以一般有两个思路。

一、先找三角数,再判断它是不是回文数。

二、先找回文数,再判断他是不是三角数。

可知我们找到的回文数,不一定能直接就有对应的整数三角数来对应,即可能  n!= k*(k+1)/2  k为整数。而且回文数的查找要么是一个数一个数的递增。要么是直接的构造 ijkji 或ijkkji 这样子输出。不过我们不能一开始就知道答案的位数,写个生成指定位数回文数的函数又比较麻烦,所以我们就选用第二种方式。

        首先题目要求找第一个大于20220514的三角回文数。   k^2/2 < n=k*(k+1)/2<(k+1)^2/2所以我们利用计算器给20220514*2开根号,上取整,即得到k+1 的值。

        

得到k+1 为 6360。 所以我们直接从 k = 6360 开始不断累加判断其是否是回文数,是就返回他的值。 

代码

k = 6360
while True:
    i = k * (k + 1) // 2
    k += 1
    s = str(i)
    if s[:len(s) // 2] == s[-1:len(s) // 2 - 1:-1]:  # 判断是否是回文数部分
        print(s)
        break

试题C:

 思路:

  假设卡片数为k,那么任选两张卡片的情况就会有 k*k 种。假设又n个人。

那么 (k-1)^2 < n <= k^2。现在已知人数为n。求k。

代码:

n = int(input())
x = int(n**0.5)  # 直接开方,int下取整
if x**2 == n: # 如果n开方就直接为整数,那么答案就直接为x
    print(x)
else:
    print(x+1) # 否则,答案就为x+1

试题D:

 分析:

仔细一看发现就是要按从小到大的顺序输出到岗员工的编号。

代码:

n = int(input())
l = []
for _ in range(n):
    l.append(input().split()[1])

l = list(set(l)) # 去重。或者就是直接sort,然后判断于前面的值是不是相同,不同就输出。
l.sort()

for i in range(len(l)):
    print(l[i])

试题E:

                

分析:

分析不出来

代码:

试题F:

 分析:

我想的是套用bfs的模板,使时间的复杂度有些高的。但是基本的案例还是能过的。

代码:

n, m = map(int, input().split())
Map = []  ## 时间图
Detect = [[0 for i in range(m)] for j in range(n)]
Detect[0][0] = 1

for _ in range(n):
    Map.append(list(map(int, input().split())))

duilie = [[Map[0][0], 0, 0]]  # 每个都记为数值,行列。
direction = [[0, 1], [1, 0], [0, -1], [-1, 0]]  # 方向

num = 0  # 染色完的个数
t = 0  # 所花费的时间

while num < n * m:
    t_min = min(duilie)[0]
    t += t_min
    N_dui = []
    for i in duilie:
        i[0] -= t_min
        if i[0] == 0:
            i[0] = 0xffffffff  # 普通队列,我就直接把变为零的值直接搞到最大,相当于去除
                               # 缺点就是重复计算的次数多,时间复杂度大
                               # 可以换为优先队列,变为0后就直接弹出,
            num += 1
            for j in range(4):  # 经典四个方向探测
                x, y = [i[1] + direction[j][0], i[2] + direction[j][1]]
                if x not in range(n) or y not in range(m) or Detect[x][y] == 1:
                    continue
                else:
                    Detect[x][y] = 1
                    N_dui.append([Map[x][y], x, y])

    duilie = duilie + N_dui # 新探测出来的点的队列加到之前的队列上


print(t)

 之后再写一个优先队列的。

试题G:

分析:

一开始看到这个题的时候感觉有点奇怪,哎呀遍历就完了。hhh

代码:

n, k = map(int, input().split())
nums = list(map(int, input().split()))
ans = 0

for i in range(n):
    res = 0
    for j in range(i, n):
        res += nums[j]
        if res // k >= 0 and res % k == 0:
            ans += 1

print(ans)

时间复杂度应该和用前缀和差不多,所以就没必要了。这个思路还是很巧妙的我感觉。

试题H:

 思路:

首先是要找素数吧,写个素数筛的代码。

代码:

试题I:

 思路:

直接就按题目写,想不到高级的方法了。

代码:

n = int(input())
nums = list(map(int, input().split()))
m = int(input())
query = []
for _ in range(m):
    query.append(list(map(int, input().split())))


def change(L):
    nums[L[1] - 1] = L[2]


def compare(L):
    n = 1
    for i in range(L[1] - 1, L[2]):
        if nums[i] < nums[L[3] - 1]:
            n += 1
    print(n, end=' ')


for i in query:
    if i[0] == 1:
        change(i)
    elif i[0] == 2:
        compare(i)

不清楚能不能过所有的测试点。

试题J:

 分析:

我们首先考虑单峰序列,一个长度为n的序列最多又多少种排列的情况?答案是2^(n-1)种。就是这样子,差不多了。

再考虑一个长度为n,和为m的数列有多少种情况。这个就用递归。

然后题目一下就说啥最后的数太大啥的,所以就来个快速幂加上

代码:

n, m = map(int, input().split())


def fi(m, i, k=0):  # 找和为m,长度为i 的单增序列的可能数。k是前一个数的值
    n = 0  # n就为结果
    if m <= k: # 当后面数的总数小于等于前面一个数时,就已经寄了 返回0
        return 0
    elif i == 1: # 没有寄,还到了i等于1 的位置就返回 1
        return 1
    for x in range(k + 1, m // i + 1):  # 遍历的位置从大于上一个,到i个平均这m 的数  
        n += fi(m - x, i - 1, x)
    return n


def ksm(a, b, c):  # 快速幂自己看吧...
    if b == 1:
        return a
    if b % 2 == 0:
        return ksm(a * a % c, b // 2, c)
    elif b % 2 != 0:
        return ksm(a * a % c, b // 2, c) * a


ans = 0
for i in range(2, n + 1):  # 长度从2遍历到n
    step = ksm(2, i - 1, 1000000007)  # 长度为i的时候的排序数量 模上 要求的数
    ans += fi(m, i) * step
    ans %= 1000000007
print((ans + 1) % 1000000007)  # 加上长度为1的一种情况

结尾

暂时先这样吧,有时间再补一下,前面两题和省赛第一场。

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值