2020年第十一届蓝桥杯软件类省赛python组

目录

  • 2020年第十一届蓝桥杯软件类省赛python组
    • 1.门牌制作
    • 2.寻找2020
    • 3.跑步训练
    • 4.蛇形填空
    • 5.排序
        • 思路:
    • 6.成绩统计
    • 7.单词分析
    • 8.数字三角形
    • 9.平面切分
        • 思路:
    • 10.装饰珠
        • 思路:

2020年第十一届蓝桥杯软件类省赛python组

本文全部题目来自此博文.
以及部分代码也是受到了他的博文的启发写出,特此表名。

如果代码有不对的地方也欢迎指正!

1.门牌制作

本题总分:5 分
【问题描述】
小蓝要为一条街的住户制作门牌号。
这条街一共有 2020 位住户,门牌号从 1 到 2020 编号。
小蓝制作门牌的方法是先制作 0 到 9 这几个数字字符,最后根据需要将字符粘贴到门牌上,例如门牌 1017 需要依次粘贴字符 1、0、1、7,即需要 1 个字符 0,2 个字符 1,1 个字符 7。
请问要制作所有的 1 到 2020 号门牌,总共需要多少个字符 2?

num = 0
for i in range(1, 2021):
    num += str(i).count('2')
print(num)

# output: 624

2.寻找2020

本题总分:5 分
【问题描述】
小蓝有一个数字矩阵,里面只包含数字 0 和 2。
小蓝很喜欢 2020,他想找到这个数字矩阵中有多少个 2020 。
小蓝只关注三种构成 2020 的方式:
• 同一行里面连续四个字符从左到右构成 2020。
• 同一列里面连续四个字符从上到下构成 2020。
• 在一条从左上到右下的斜线上连续四个字符,从左上到右下构成 2020。
例如,对于下面的矩阵:
220000
000000
002202
000000
000022
002020
一共有 5 个 2020。其中 1 个是在同一行里的,1 个是在同一列里的,3 个是斜线上的。
小蓝的矩阵比上面的矩阵要大,由于太大了,他只好将这个矩阵放在了一个文件里面,在试题目录下有一个文件 2020.txt,里面给出了小蓝的矩阵。
请帮助小蓝确定在他的矩阵中有多少个 2020。
PS: 感谢码友:Gygert 提供的2020.txt文件:2020.txt
正确答案:16520
对于2020的判断有个地方不要忽略:
2020年第十一届蓝桥杯软件类省赛python组_第1张图片
如果仅仅使用i+3<300andj+3<300是会忽略掉边缘部分数据的

matrix = []
f = open("./2020.txt", "r")  # 这里我自己建了一个文件夹,里面存的是题目给的例子
while True:
    data = f.readline()  # 每次取出一行数据, 不过这样确实是浪费了好多时间。。。
    if data[-1] != '\n':  # 最后一行数据的最后一个元素为数字【0, 2】
        matrix.append(list(data))
        break
    else:
        data = data[:-1]
    a = list(data)
    matrix.append(a)
f.close()
row = len(matrix)  # 行
col = len(matrix[0])  # 列
count = 0
for i in range(row):
    for j in range(col):
        if matrix[i][j] == '2':  # 取出的数据类型都是字符串所以用字符'2'
            if j + 3 < col:
                if matrix[i][j] + matrix[i][j + 1] + matrix[i][j + 2] + matrix[i][j + 3] == "2020":
                    count += 1
            if i + 3 < row:
                if matrix[i][j] + matrix[i + 1][j] + matrix[i + 2][j] + matrix[i + 3][j] == "2020":
                    count += 1
            if i + 3 < row and j + 3 < col:
                if matrix[i][j] + matrix[i + 1][j + 1] + matrix[i + 2][j + 2] + matrix[i + 3][j + 3] == "2020":
                    count += 1
print(count)

3.跑步训练

本题总分:10 分
【问题描述】
小蓝每天都锻炼身体。
正常情况下,小蓝每天跑 1 千米。
如果某天是周一或者月初(1 日),为了激励自己,小蓝要跑2千米。如果同时是周一或月初,小蓝也是跑2千米。
小蓝跑步已经坚持了很长时间,从2000年1月1日周六(含)到2020年10月1日周四(含)。
请问这段时间小蓝总共跑步多少千米?

import datetime
start = datetime.date(2000,1,1)
end = datetime.date(2020,10,1)
days = datetime.timedelta(days=1)  # 用以可用于计算的一天  timedelta代表两个时间之间的时间差
res = 0
while start <= end:
    if start.day == 1 or start.weekday() == 0:
        res += 2
    else:
        res += 1
    start += days
print(res)


# output: 8879

4.蛇形填空

本题总分:10 分
【问题描述】
如下图所示,小明用从1开始的正整数“蛇形”填充无限大的矩阵。
1 2 6 7 15 …
3 5 8 14 …
4 9 13 …
10 12 …
11 …

容易看出矩阵第二行第二列中的数是 5。
请你计算矩阵中第 20 行第 20 列的数是多少?

# 此题可以暴力破解
matrix = [[0 for i in range(50)] for i in range(50)]
matrix[0][0] = 1
row = len(matrix)
col = len(matrix)
i=0
j=0
for k in range(20):
    if i == 0 and j % 2 == 0:
        j += 1
        matrix[i][j] = matrix[i][j - 1] + 1
        while j > 0:
            matrix[i + 1][j - 1] = matrix[i][j] + 1
            i += 1
            j -= 1
    if j == 0 and i % 2 == 1:
        i += 1
        matrix[i][j] = matrix[i - 1][j] + 1
        while i > 0:
            matrix[i - 1][j + 1] = matrix[i][j] + 1
            i -= 1
            j += 1
print(matrix[19][19])


# 761

再多划几行不难发现斜对角数字的规律:每次增加4的n倍
2020年第十一届蓝桥杯软件类省赛python组_第2张图片

n = 20
Sum = 4
ans = 1
for i in range(2, n + 1):
    ans += Sum
    Sum += 4
print(ans)


# 761

5.排序

本题总分:15 分
【问题描述】
小蓝最近学习了一些排序算法,其中冒泡排序让他印象深刻。
在冒泡排序中,每次只能交换相邻的两个元素。
小蓝发现,如果对一个字符串中的字符排序,只允许交换相邻的两个字符,则在所有可能的排序方案中,冒泡排序的总交换次数是最少的。
例如,对于字符串 lan 排序,只需要 1 次交换。
对于字符串 qiao 排序,总共需要 4 次交换。
小蓝找到了很多字符串试图排序,他恰巧碰到一个字符串,需要 100 次交换,可是他忘了吧这个字符串记下来,现在找不到了。
请帮助小蓝找一个只包含小写英文字母且没有字母重复出现的字符串,对该串的字符排序,正好需要 100 次交换。
如果可能找到多个,请告诉小蓝最短的那个。
如果最短的仍然有多个,请告诉小蓝字典序最小的那个。
请注意字符串中可以包含相同的字符。

思路:

本题的话事实上有更优质的文章讲解,这是一个非常详细的博文
这里呢我就简单的说一说。

一段字符串两两交换,使得其成为正序。只有当且仅当其刚好为反序的时候交换次数最多。
而通过计算也可以知道当字符串有15个字符且各不相同的时候交换次数为105次,也即:onmlkjighfedecba,当字符串不到15个字符的时候交换次数是绝对到不了100次的。因为题目要求字典序最小的字符串,所以将’j’提至最前刚好满足100次,即答案为:jonmlkihgfedcba。

6.成绩统计

时间限制: 1.0s 内存限制: 512.0MB 本题总分:15 分
【问题描述】
小蓝给学生们组织了一场考试,卷面总分为 100 分,每个学生的得分都是一个 0 到 100 的整数。
如果得分至少是 60 分,则称为及格。如果得分至少为 85 分,则称为优秀。
请计算及格率和优秀率,用百分数表示,百分号前的部分四舍五入保留整数。
【输入格式】
输入的第一行包含一个整数 n,表示考试人数。
接下来 n 行,每行包含一个 0 至 100 的整数,表示一个学生的得分。
【输出格式】
输出两行,每行一个百分数,分别表示及格率和优秀率。
百分号前的部分四舍五入保留整数。
【样例输入】
7
80
92
56
74
88
100
0
【样例输出】
71%
43%

n = int(input())
you = 0
jige = 0
for i in range(n):
    a = int(input())
    if a >= 60:
        jige += 1
        if a >= 85:
            you += 1
jige = format(jige / n, '.2f')  # format方法可以四舍五入,但返回的是字符串形式
you = format(you / n, '.2f')
print(f'{jige[2:]}%')
print(f'{you[2:]}%')

7.单词分析

时间限制: 1.0s 内存限制: 512.0MB 本题总分:20 分
【问题描述】
小蓝正在学习一门神奇的语言,这门语言中的单词都是由小写英文字母组成,有些单词很长,远远超过正常英文单词的长度。小蓝学了很长时间也记不住一些单词,他准备不再完全记忆这些单词,而是根据单词中哪个字母出现得最多来分辨单词。
现在,请你帮助小蓝,给了一个单词后,帮助他找到出现最多的字母和这个字母出现的次数。
【输入格式】
输入一行包含一个单词,单词只由小写英文字母组成。
【输出格式】
输出两行,第一行包含一个英文字母,表示单词中出现得最多的字母是哪个。
如果有多个字母出现的次数相等,输出字典序最小的那个。
第二行包含一个整数,表示出现得最多的那个字母在单词中出现的次数。
【样例输入】
lanqiao
【样例输出】
a
2
【样例输入】
longlonglongistoolong
【样例输出】
o
6
【评测用例规模与约定】
对于所有的评测用例,输入的单词长度不超过 1000。

word = input()
new_word = sorted(list(set(word)))
max_word = None
max_count = 0
for i in new_word:
    if max_count < word.count(i):
        max_word = i
        max_count = word.count(i)
print(max_word)
print(max_count)

8.数字三角形

时间限制: 1.0s 内存限制: 512.0MB 本题总分:20 分
【问题描述】
上图给出了一个数字三角形。
从三角形的顶部到底部有很多条不同的路径。
对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和。
路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右边的那个数。
此外,向左下走的次数与向右下走的次数相差不能超过 1。
【输入格式】
输入的第一行包含一个整数 N (1 < N ≤ 100),表示三角形的行数。
下面的N 行给出数字三角形。
数字三角形上的数都是 0 至 100 之间的整数。
【输出格式】
输出一个整数,表示答案。
【样例输入】
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
【样例输出】
27

# 本题依旧可以暴力破解但效率太低,标准解法应该是使用动态规划
N = int(input())
matrix = []
for i in range(N):
    matrix.append(list(map(int, input().split())))

for i in range(N):
    for j in range(i):
        matrix[i][j] += max(matrix[i - 1][j - 1], matrix[i - 1][j])

print(matrix[N - 1][N // 2] if N % 2 == 1 else max(matrix[N - 1][N // 2 - 1], matrix[N - 1][N // 2]))
# 根据题目要求:符合要求的最后的数一定是最后一行的中间的数

9.平面切分

时间限制: 1.0s 内存限制: 512.0MB 本题总分:25 分
【问题描述】
平面上有 N 条直线,其中第 i 条直线是 y = Ai · x + Bi。
请计算这些直线将平面分成了几个部分。
【输入格式】
第一行包含一个整数 N。
以下 N 行,每行包含两个整数 Ai, Bi。
【输出格式】
一个整数代表答案。
【样例输入】
3
1 1
2 2
3 3
【样例输出】
6
【评测用例规模与约定】
对于 50% 的评测用例,1 ≤ N ≤ 4, −10 ≤ Ai, Bi ≤ 10。
对于所有评测用例,1 ≤ N ≤ 1000, −100000 ≤ Ai, Bi ≤ 100000。

思路:

画图测试时发现(每种情况都考虑,平行、相交):不论什么情况每增加一条直线都会增加一个平面,每次增加直线时与已存在直线进行比较,当有n个交点也即与n条直线相交时,相应的平面数量也增加n。

N = int(input())
li = []  # 直线列表
point_count = 0
for _ in range(N):
    a, b = map(int, input().split())
    if [a, b] in li:  # 重复线去掉
        continue
    li.append([a, b])
    point = []  # 每条线与之前所有线的交点
    for i in range(len(li) - 1):
    	if li[i][0] - li[len(li) - 1][0] == 0:
    		continue
        x = (li[len(li) - 1][1] - li[i][1]) / (li[i][0] - li[len(li) - 1][0])
        y = x * li[i][0] + li[i][1]
        if [x, y] in point:  # 保存不同的交点
            continue
        point.append([x, y])
    point_count += len(point)


print(len(li) + point_count + 1)

10.装饰珠

时间限制: 1.0s 内存限制: 512.0MB 本题总分:25 分
【问题描述】
在怪物猎人这一款游戏中,玩家可以通过给装备镶嵌不同的装饰珠来获取相应的技能,以提升自己的战斗能力。
已知猎人身上一共有 6 件装备,每件装备可能有若干个装饰孔,每个装饰孔有各自的等级,可以镶嵌一颗小于等于自身等级的装饰珠 (也可以选择不镶嵌)。
装饰珠有 M 种,编号 1 至 M,分别对应 M 种技能,第 i 种装饰珠的等级为 Li,只能镶嵌在等级大于等于 Li 的装饰孔中。
对第 i 种技能来说,当装备相应技能的装饰珠数量达到 Ki 个时,会产生Wi(Ki) 的价值。镶嵌同类技能的数量越多,产生的价值越大,即 Wi(Ki − 1) 对于给定的装备和装饰珠数据,求解如何镶嵌装饰珠,使得 6 件装备能得到的总价值达到最大。
【输入格式】
输入的第 1 至 6 行,包含 6 件装备的描述。其中第 i 的第一个整数 Ni 表示第 i 件装备的装饰孔数量。后面紧接着 Ni 个整数,分别表示该装备上每个装饰孔的等级 L(1 ≤ L ≤ 4)。
第 7 行包含一个正整数 M,表示装饰珠 (技能) 种类数量。
第 8 至 M + 7 行,每行描述一种装饰珠 (技能) 的情况。每行的前两个整数Lj(1 ≤ Lj ≤ 4) 和 Pj(1 ≤ Pi ≤ 7) 分别表示第 j 种装饰珠的等级和上限。接下来Pj 个整数,其中第 k 个数表示装备该中装饰珠数量为 k 时的价值 Wj(k)。
【输出格式】
输出一行包含一个整数,表示能够得到的最大价值。
【样例输入】
1 1
2 1 2
1 1
2 2 2
1 1
1 3
3
1 5 1 2 3 5 8
2 4 2 4 8 15
3 2 5 10
【样例输出】
20
【样例说明】
按照如下方式镶嵌珠子得到最大价值 18,括号内表示镶嵌的装饰珠的种类编号:
1: (1)
2: (1) (2)
3: (1)
4: (2) (2)
5: (1)
6: (2)
4 颗技能 1 装饰珠,4 颗技能 2 装饰珠 W1(4) + W2(4) = 5 + 15 = 20。
【评测用例规模与约定】
对于 30% 的评测用例,1 ≤ Ni ≤ 10, 1 ≤ M ≤ 20, 1 ≤ Wj(k) ≤ 500;
对于所有评测用例,1 ≤ Ni ≤ 50, 1 ≤ M ≤ 10000, 1 ≤ Wj(k) ≤ 10000。

这道题我是看了1个多小时才勉强看懂题目的。。。

思路:

题目要求找出总价值最大的,在进行比较的时候发现越是价值跨幅比较大的,一般都会被采纳到。
但是不一定每个装饰珠都会把技能拉满,所以要先剔除无用的。
最后把最终价值相加即为答案。

这道题的代码我自己都觉得繁琐,如果大佬有更好的想法,欢迎指点!
这道题我自己写了几个简单的测试样例,算是勉强没问题。如果你们发现了啥问题我在改。

def eliminate(bead, max_dic):  # 对用不到的价值剔除,同时对bead进行更新
    for i in bead:
        if i[1] > max_dic[i[0]]:
            for _ in range(i[1] - max_dic[i[0]]):
                i.pop()
                i[1] -= 1
    if len(bead[-1]) == 2:  # 此时本类装饰珠价值不被用到,剔除
        res = bead.pop()[0]
        del dic[res]
        del max_dic[res]
    # print(bead)


N = []
for i in range(6):
    N.append(list(map(int, input().split())))
dic = {
     }  # 用来存储装饰孔各等级的数量
max_dic = {
     }  # 存储每个装饰孔各等级可以放置装饰珠的最大个数
for i in N:
    for j in i[1:]:
        if j in dic:
            dic[j] += 1
            max_dic[j] += 1
        else:
            dic[j] = 1
            max_dic[j] = 1
# print(dic)

for i in range(max(dic) - 1, 0, -1):
    if i not in max_dic:
        max_dic[i] = max_dic[i + 1]
    max_dic[i] += max_dic[i + 1]
# print(max_dic)

M = int(input())
bead = []
for i in range(M):
    bead.append(list(map(int, input().split())))
eliminate(bead, max_dic)  # 对用不到的价值剔除

count = 0
while count != max_dic[1] + 2 * len(bead):
    te = None
    tmp = 0
    for i in range(len(bead) - 1, -1, -1):  # 找出等级拉满收益最大的等级,再次进行剔除
        if len(bead[i]) == 3:
            if tmp < bead[i][-1]:  # 找出价值跨越最大的地方,这里的技能一定是点满的
                te = i
                tmp = bead[i][-1]
                continue
        if tmp < bead[i][-1] - bead[i][-2]:  # 找出价值跨越最大的地方,这里的技能一定是点满的
            te = i
            tmp = bead[i][-1] - bead[i][-2]
    # print(dic)
    # print(max_dic)
    if max_dic[bead[te][0]] > dic[bead[te][0]] and bead[te][0] != max(dic):
        max_dic[bead[te][0] + 1] -= max_dic[bead[te][0]] - dic[bead[te][0]]
        for i in range(max_dic[bead[te][0]] - dic[bead[te][0]]):
            bead[bead[te][0]].pop()
    if len(bead[-1]) == 2:  # 此时本类装饰珠价值不被用到,剔除
        res = bead.pop()[0]
        del dic[res]
        del max_dic[res]
    # print(bead)
    Sum = 0
    for i in bead[::-1]:
        if Sum + i[1] <= max_dic[i[0]]:
            Sum += i[1]
        else:
            Sum += i[1]
            for j in range(Sum - max_dic[i[0]]):
                Sum -= 1
                i.pop()
                i[1] -= 1
    count = 0
    for i in range(len(bead)):
        count += len(bead[i])
    if count < max_dic[1] + 2 * len(bead):
        break

Num = 0
for i in bead:
    Num += i[-1]
print(Num)

本文借鉴或许多文章,把他们的链接都提出来是分享也是记录我学习的过程与见证。

你可能感兴趣的:(蓝桥杯,python,python)