第十一届蓝桥杯大赛软件赛省赛(Python大学组)

2020年蓝桥杯  省赛真题
Python大学组

        试题A:门牌制作
        试题B:寻找2020
        试题C:跑步锻炼
        试题D:蛇形填数
        试题E:排序
        试题F:成绩统计
        试题G:单词分析
        试题H:数字三角形
        试题I:平面切分
        试题J:装饰珠


试题A:门牌制作     (5分)

【题目描述】

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

【答案提交】

        这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只输出这个整数,输出多余的内容将无法得分。

【解析与方法】

        可以直接1~2020全部的数字转化成一个字符串,然后再调用字符串中的count函数可以直接得出答案为624。

【Python程序与代码】

s = "".join([str(i) for i in range(1,2021)])
print(s.count('2'))

最终结果: 624


试题B:寻找2020     (5分)

【题目描述】

扫描二维码关注公众号,回复: 17277168 查看本文章

        小蓝有一个数字矩阵,里面只包含数字0和2。小蓝很喜欢 2020,他想找到这个数字矩阵中有多少个2020。小蓝只关注三种构成2020的方式
        1.同一行里面连续四个字符从左到右构成 2020。
        2.同一列里面连续四个字符从上到下构成2020
        3.在一条从左上到右下的斜线上连续四个字符,从左上到右下构成2020
例如,对于下面的矩阵:

220000
000000
002202
000000
000022
002020

        共有5个2020。其中1个是在同一行里的,1个是在同一列里的,3个 是斜线上的。
小蓝的矩阵比上面的矩阵要大,如下给出了小蓝的矩阵。
        请帮助小蓝确定在他的矩阵中有多少个2020。

【答案提交】

        这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只输出这个整数,输出多余的内容将无法得分。

【解析与方法】

        根据文本txt文件,我们可以得知数字矩阵的大小为300*300.根据题意,可以直接暴力求解,可以直接枚举每个位置 s[ i ][ j ] 然后判断s[ i ][ j+1 ],s[ i ][ j+2 ],s[ i ] [ j+3 ]是否符合要求,s[ i+1 ][ j ],s[ i+2 ][ j ],s[ i+3 ][ j ]是否符合要求,s[ i+1 ][ j+1 ],s[ i+2 ][ j+2 ],s[ i+3 ][ j+3 ]是否符合要求,同时需要保证不要越界。即可得出正确答案16520。

【Python程序代码】

s = []
for i in range(300):
  t = input()
  s.append(t)
res = 0
for i in range(300):
  for j in range(300):
    if i+3<300 and s[i][j]=='2' and s[i+1][j]=='0' and s[i+2][j]=='2' and s[i+3][j]=='0':
      res+=1
    if j+3<300 and s[i][j]=='2' and s[i][j+1]=='0' and s[i][j+2]=='2' and s[i][j+3]=='0':
      res+=1
    if i+3<300 and j+3<300 and s[i][j]=='2' and s[i+1][j+1]=='0' and s[i+2][j+2]=='2' and s[i+3][j+3]=='0':
      res+=1
print(res)

最终结果:16520 ​​​​​​​


 试题C:跑步锻炼     (10分)

【题目描述】

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

【答案提交】

        这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只输出这个整数,输出多余的内容将无法得分。

【解析与方法】

         本题可以直接模拟一下题意,遍历过去就行。可以得到答案8879.

【Python程序代码】

import datetime

start = datetime.date(2000, 1, 1)
end = datetime.date(2020, 10, 1)
days = datetime.timedelta(days=1)
ans = 0

while end >= start:
    if start.day == 1 or start.weekday() == 0:
        ans += 2
    else:
        ans += 1
    start += days
print(ans)

最终结果:8879 


试题 D:蛇形填数     (10分)

【题目描述】

        如下图所示,小明用从1开始的正整数“蛇形”填充无限大的矩阵。

1 2 6 7 15 ...
3 5 8 14 ...
4 9 13 ...
10 12 ...
11 ...
...

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

【答案提交】

        这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只输出这个整数,输出多余的内容将无法得分。

【解析与方法】

        根据对角线上元素特点不难发现1、5、13、25。1+4=5、5+8=13、13+12=25、所以第20行第20列应该为1 + 1*4 + 2*4 + 3*4 + ... + 19*4 = 761。

【Python程序代码】

print(1 + (1+19)*19//2*4)

最终结果:761 


 试题E、排序     (15分)

【题目描述】

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

【答案提交】

        这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只输出这个整数,输出多余的内容将无法得分。

【解析与方法】

        简单分析:

                        字符串长度 1             需要的交换次数 0                          a

                        字符串长度 2             需要的交换次数 1                         ba

                        字符串长度 3             需要的交换次数 1+2=3                cba

                        字符串长度 4             需要的交换次数 3+4=7                dcba 

                        字符串长度 5             需要的交换次数 7+5=12             edcba 

        即每次在上一个字符串长度上加上将第一个字符移到最后一位去。所以当交换次数达到100说明字符串的长度至少为n且 (n+1)*n>=100 and (n-1)*n<100 得n=14.即至少需要15个字符 此时s = "onmlkjihgfedcba"的时候需要的交换次数为14*15/2=105次那么答案即为将第6个字母 j 换到第一个来就可以保证字典序最小了。所以答案为s = "inmlkjhgfedcba"

【Python程序代码】

s,k = "",0
for i in range(1,100):
    if (i+1)*i>=200 and (i-1)*i<200:
        k=i
        break
for i in range(k,-1,-1):
    s += chr(ord('a')+i)
k = (k+1)*k//2 - 100
s = s[k] + s[:k] + s[k+1:]
print(s)

 最终结果:inmlkjhgfedcba


 试题F:成绩统计     (15分)

【题目描述】

        小蓝给学生们组织了一场考试,卷面总分为 100分,每个学生的得分都是一个0到100的整数。
        如果得分至少是 60分,则称为及格。如果得分至少为 85 分,则称为优秀请计算及格率和优秀率,用百分数表示,百分号前的部分四舍五入保留整数。

【输入描述】

        输入的第一行包含一个整数n,表示考试人数。
        接下来n行,每行包含一个0至100的整数,表示一个学生的得分

【输出描述】

        输出两行,每行一个百分数,分别表示及格率和优秀率。百分号前的部分四舍五入保留整数。

【输入样例】

7
80
92
56
74
88
100
0

【输出样例】

71%
43%

【测试用例与规模】

        对于所以的评测用例,1<n<10000。

【解析与方法】

        简单题,送分。

【Python程序代码】

n = int(input())
avl,mi,ma=0,100,0
for i in range(n):
  num = int(input())
  avl += num
  if num<mi:
    mi = num
  if num>ma:
    ma = num
print(ma)
print(mi)
print("%.2lf"%(round(avl/n,2)))

试题​​​​​​​G:单词分析     (20分)

【题目描述】

        小蓝正在学习一门神奇的语言,这门语言中的单词都是由小写英文字母组成,有些单词很长,远远超过正常英文单词的长度。小蓝学了很长时间也记不住一些单词,他准备不再完全记忆这些单词,而是根据单词中哪个字母出现得最多来分辨单词。
        现在,请你帮助小蓝,给了一个单词后,帮助他找到出现最多的字母和这个字母出现的次数。

【输入描述】

       输入一行包含一个单词,单词只由小写英文字母组成。
        对于所有的评测用例,输入的单词长度不超过1000。

【输出描述】

        输出两行,第一行包含一个英文字母,表示单词中出现得最多的字母是哪个。如果有多个字母出现的次数相等,输出字典序最小的那个。
        第二行包含一个整数,表示出现得最多的那个字母在单词中出现的次数。

【输入样例】

longlonglongistoolong

【输出样例】

o
6

【解析与方法】

         直接统计字符串中每个字符出现的次数。

【Python程序代码】

s = input()
res,cnt = 'a',0
for i in s:
  t = s.count(i)
  if t>=cnt:
    if t==cnt and i>res:
      continue
    res,cnt = i,t
print(res)
print(s.count(res))

试题H:数字三角形     (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

【解析与方法】

         属于是线性DP的变种了,数字三角形母题就是dp[ i ][ j ] = max( dp[ i-1 ][ j-i ] + dp[ i-1 ][ j ]) + a[ i ][ j ],然而本题还有一个另外的限制条件为:向左坐走的次数与向右走的次数之差不能超过1.所以我们可以考虑用一个三维的dp[ i ][ i ][ k ]每次把向左走和向右走的次数记录下来,如果左边大于右边即:dp[ i-1 ][ j-1 ][ 0 ] > dp[ i-1 ][ j ][ 0 ] 则:dp[ i ][ j ][ 0 ] = dp[ i-1 ][ j-1 ][ 0 ]  + a[ i ][ j ] 。      dp[ i ][ j ][ 1 ] = dp[ i-1 ][ j-1 ][ 1 ] + 1、dp[ i ][ j ][ 2 ] = dp[ i-1 ][ j-1 ][ 2 ] ,大于的话同理可得。最后再枚举dp数组的最后一行,找出最大的符合条件的数。

【Python程序代码】

n = int(input())
dp = [[[0,0,0]for i in range(110)]for j in range(110)]
a,res  = [] , 0
a.append([0,0,0,0])
for i in range(n):
    l = [0] + list(map(int,input().split()))
    a.append(l)
dp[1][1][0] = a[1][1]
for i in range(2,n+1):
    for j in range(1,i+1):
        if dp[i-1][j-1][0] < dp[i-1][j][0]:
            dp[i][j][0] = dp[i-1][j][0] + a[i][j]
            dp[i][j][1] = dp[i-1][j][1]
            dp[i][j][2] = dp[i-1][j][2] + 1
        else:
            dp[i][j][0] = dp[i-1][j-1][0] + a[i][j]
            dp[i][j][1] = dp[i-1][j-1][1] + 1
            dp[i][j][2] = dp[i-1][j-1][2]
for i in range(1,n+1):
    if dp[n][i][0] > res and dp[n][i][1] - dp[n][i][2] in [0,-1,1]:
        res = dp[n][i][0]
print(res)

试题 I:平面切分     (25分)

【题目描述】

        平面上有N条直线,其中第i条直线是y=Aix+Bi。
        请计算这些直线将平面分成了几个部分​​​​​​​

【输入描述】

        第一行包含一个整数N。
        以下N 行,每行包含两个整数 Ai,Bi。
        其中,1<N <1000,-10⁵ < Ai, Bi< 10⁵。

【输出描述】

        一个整数代表答案。

【解析与方法】

         本题主要考察思维,先画几个图找找规律,可以发现当增加一条直线的时候,若这条直线与其它直线作用新增加的平面的个数为:新增加的点的个数+1.得到了这个规律的话该题基本解决了。

【Python程序代码】

n = int(input())
line,res = set(),1
def solve(a,b):
    s = set()
    for i in line:
        A,B = i[0],i[1]
        if a==A:
            continue
        x = (b-B)/(A-a)
        y = A*x+B
        s.add((x,y))
    return len(s)+1
for i in range(n):
    a,b = map(int,input().split())
    if (a,b) in line:
        continue
    res += solve(a,b)
    line.add((a,b))
print(res)

试题J:装饰珠     (25分)

【题目描述】

        ​​​​​​​在怪物猎人这一款游戏中,玩家可以通过给装备镶嵌不同的装饰珠来获取相应的技能,以提升自己的战斗能力。
        已知猎人身上一共有6件装备,每件装备可能有若干个装饰孔,每个装饰孔有各自的等级,可以镶嵌一颗小于等于自身等级的装饰珠(也可以选择不镶)
        装饰珠有M种,编号1至M,分别对应M种技能,第种装饰珠的等级为 Li,只能镶嵌在等级大于等于 Li的装饰孔中。
        对第i种技能来说,当装备相应技能的装饰珠数量达到Ki个时,会产生Wi(Ki)的价值。镶嵌同类技能的数量越多,产生的价值越大,即Wi(Ki-1)< Wi(K)。但每个技能都有上限 Pi(1≤P≤7),当装备的珠子数量超过Pi时,只会产生Wi(Pi)的价值。
        对于给定的装备和装饰珠数据,求解如何镶嵌装饰珠,使得 6件装备能得到的总价值达到最大。

【输入描述】

        输入的第1至6行包含6件装备的描述。其中第i行的第一个整数Ni表示第i件装备的装饰孔数量。后面紧接着Ni个整数,分别表示该装备上每个装饰孔的等级数(1≤L≤4)。
        第7行包含一个正整数M,表示装饰珠(技能)种类数量
        第8至M+7行,每行描述一种装饰珠(技能)的情况。每行的前两个整数Lj(1≤Lj≤4)和Pj(1≤P≤7)分别表示第j种装饰珠的等级和上限。接下来P个整数,其中第k个数表示该装备中装饰珠数量为k时的价值Wj(k)。其中:1<Ni< 50,1≤M ≤10⁴,1≤Wi(k) ≤10⁴.

【输出描述】

        ​​​​​​​输出一行包含一个整数,表示能够得到的最大价值。

【样例输入】

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

【解析与方法】        

        题目有点绕,多读两遍题目很重要,6件装备,每件装备有若干个装饰孔,可以不用考虑这么多,直接把所有装饰孔合在一起考虑,建立一个sum数组存储 i 等级的装饰孔数 sum[ i ],考虑到装饰孔等级数(1~4)可以直接建4个数组存储,每种等级的Wj(k)。显而易见的背包问题。如果我们考虑从低等级到高等级的装入方法的话,枚举高等级的时候有需要分别考虑低等级的还剩多少个,相当的复杂,换个思路,如果先枚举高等级在枚举低等级就可以少考虑很多,因为低等级装饰珠可以放到高等级的装饰孔中,反过来就不行。

        我们定义 dp[ i ] [ j ]​ 表示前 i​​ 种装饰珠(装饰珠的等级从高到低),背包容量为 j​​ 时的方案数。那么 dp[i][j] = max(dp[ i-1 ][ j ] , dp[ i-1 ][ j-k ] + Wik(其中 k​ 表示第 i​ 种装饰珠的选取个数)。注意当我们从高等级步入低等级时,需要将最大背包容量扩大 cnt(cnt​ 表示低等级的装饰孔的个数)。由于第 i 种装饰珠的状态只会有第 i -1 种装饰珠的状态转移得到,于是我们可以优化掉 dp数组的第一维。

【Python程序代码】

vec1,vec2,vec3,vec4,vec,dp,sum = [],[],[],[],[],[0]*310,[0]*10
for i in range(1, 7):
    mp = list(map(int, input().split()))
    for i in range(1, len(mp)):
        sum[mp[i]] += 1
m = int(input())
for i in range(1, m + 1):
    mp = list(map(int, input().split()))
    b = []
    for j in range(2, len(mp)):
        x = mp[j]
        b.append(x)
    if mp[0] == 1:
       vec1.append(b)
    if mp[0] == 2:
        vec2.append(b)
    if mp[0] == 3:
        vec3.append(b)
    if mp[0] == 4:
        vec4.append(b)
V = 0
cnt = 0
for l in range(4, 0, -1):
    V += sum[l]
    if l == 1:
        vec = vec1
    elif l == 2:
        vec = vec2
    elif l == 3:
        vec = vec3
    elif l == 4:
        vec = vec4
    for i in vec:
        k = int(V)
        while k >= 0:
            for j in range(0, len(i)):
                if k - j - 1 >= 0:
                     if dp[k - j - 1] + i[j] > dp[k]:
                            dp[k] = dp[k - j - 1] + i[j]
                else:
                     break
            k -= 1
ans = 0
for h in range(0, V + 1):
    ans = max(ans, dp[h])

print(ans)

猜你喜欢

转载自blog.csdn.net/w2563216521/article/details/133848983
今日推荐