第十三届蓝桥杯青少组Python国赛真题解

单选题1:执行下面的代码,输出的结果是(  )。

· 

· 

l = ['a','b','c','d','e','f','g']print(l.pop(2), len(l))

A)a 6    (B)a 7    (C)b 6    (D)c 6

答案:D  list.pop(index)删除列表index位置的元素,返回该元素。

单选题2:执下面表达式,结果是True的是( )。(A)9 != 9  (B)9>8>7  (C)9 % 2 == 2  (D)True and False

答案: 9>8>7相当于9>8 and 8>7,Python语法特性,其它语言少见这种表达式。

单选题3:执行下面的代码,输出的结果是(  )。

· 

· 

d = {'lan':1,'qiao':2,'qing':3,'shao':4}print(d.pop(max(d.keys()), 0))

A)2  (B)4  (C)qiao  (D)shao

答案:B  pop的第二个参数是默认值,即主键不存在时返回的值。

单选题4:以下有关函数的描述,正确的是( )。(A)函数的定义必须在程序的开头
B)函数定义后需要调用才能执行
C)函数体与关键字 def 必须对齐
D)函数定义后,其程序可以自动执行

答案:B

单选题5:对于打开文件函数open(<文件路径名>,<打开模式>)中的打开模式描述正确的是( )。(A)'r' 表示只读模式打开文件,如果文件不存在,就会抛出异常
B)'w' 表示写模式打开文件,如果文件存在,就会在文件尾继续写
C)'a' 表示追加模式打开文件,如果文件不存在,就会抛出异常(D'b' 表示二进制文件模式打开文件,可以单独作为open函数的参数。

答案:A

编程题1:  给定一个正整数,然后将N中各位上的数字相乘,并输出最后的乘积。
  例如:N=132 ,各数位相乘后的乘积为6(6=1*3*2))输入描述:输入一个正整数输出描述: 将N中各位上的数字相乘,并输出最后的乘积
样例输入:132样例输出:6代码:

· 

· 

· 

· 

· 

· 

· 

· 

· 

N=int(input())rst=1while N>0:    rst *= N % 10    if rst==0:        break    N//=10
print(rst)

解说:N % 10 与 N //=10 可以把一个数从个位开始分开每位数,本题求的是乘积,如果有数位是0则结果是0,结束。

编程题2:  在一根电线上落有N只小鸟,有的小鸟头向左看,有的小鸟头向右看,且每只小鸟只能看到它视线前的那一只小鸟。   给定N只小鸟头的朝向,头向左看的小鸟使用小写字母“q”表示,头向右看的小鸟用小写字母“p”表 示,请你计算出N只小鸟中有多少只小鸟被0只小鸟看到,多少只小鸟被1只小鸟看到,多少只小鸟被2只小鸟看到。   例如:N=6,6只小鸟头的朝向分别为p,q,p,p,q,q。

    第1只 第2只 第3只 第4只 第5只 第6只

  如图:有2只小鸟被0只小鸟看到(第3只和第6只);有2只小鸟被1只小鸟看到(第1只和第2只);有2 只小鸟同时被2只小鸟看到(第4只和第5只)。 

  则输出三个数字分别为2,2,2。

输入描述: 第一行输入一个正整数N(3≤N≤1000),表示有N只小鸟落在电线上第二行输入N个字符,字符只能为“q”和“p”,“q”表示小鸟头向左看,“p”表示小鸟头向右看,字 符之间以一个英文逗号隔开 输出描述:一行输出三个整数,分别为有几只小鸟被0只小鸟看到;有几只小鸟被1只小鸟看到;有几只小鸟被2只小鸟看到;整数之间一个英文逗号隔开样例输入:6 p,q,p,p,q,q 样例输出: 2,2,2代码:

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

N=int(input())lst=input().split(",")rst=[0]*Nfor i in range(N):    if i-1>-1 and lst[i-1]=='p':        rst[i]+=1    if i+1<N and lst[i+1]=='q':        rst[i]+=1count=str(rst.count(0)),str(rst.count(1)),str(rst.count(2))print(",".join(count))

解说:初始化一个长度为N每个值是0的列表与每个鸟对应,检查每个鸟的左右来修改列表元素值。

编程题3:  某班级男生人数为X人,女生人数为Y人,现全班同学围成一个圆圈,并按照顺时针方向为每名同学编号(编号从1X+Y)。现给出一个正整数 K2<K<(X+Y)】,从编号为1的同学开始顺时针方向报数,报到K的同学退出圆圈,下一名同学继续从1报数,再次报到K的同学退出圆圈。如此循环,直到剩余人数为X时游戏结束。  请你计算出游戏开始时X名男生分别应该排在什么位置,才能保证每次离开的都是女生,游戏结束时剩余X人都是男生。并将游戏开始时每名男生的位置编号按照从小到大顺序输出。  例如:X=5Y=3K=38名同学按照如下顺序排列,可以使3轮报数过后最后剩余的 名同学都为男生(蓝色为男生位置,红色为女生位置)。   名男同学的编号分别为24578  输入描述:输入三个正整数 XYK3X1003Y1002<K<(X+Y)),X表示男生人数,表示女生人数,报数为 的同学退出圆圈,三个正整数之间以一个空格隔开  输出描述:将每名男生位置编号按照从小到大的顺序输出,编号之间以一个空格隔开  样例输入:5 3 3  样例输出:2 4 5 7 8代码:

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

X,Y,K=map(int,input().split())lst=[[i+1, True] for i in range(X+Y)]out=0index=0count=0while out<Y:    index%=X+Y    if lst[index][1]:        count+=1        if count==K:            out+=1            count=0            lst[index][1]=False        index+=1rst=[]for item in lst:    if item[1]:        rst.append(str(item[0]))print(" ".join(rst))

解说:这是约瑟夫环,只要在每个对象中保留它的位置,最后剩下的对象中的位置就是开始要处的位置。

编程题4:  老师要奖励N名成绩优秀的同学,首先N名同学按随机顺序排成一排,且每名同学都对应一个成绩(成绩各不相同),然后按照如下规则进行奖励。  规则:  1)每名同学至少奖励1支铅笔;  2)每一名同学拿到铅笔后,都会和左右相邻的同学作比较,如果相邻的同学成绩比自己高,那么铅笔数也一定比自己多,如果相邻的同学成绩比自己低,那么铅笔数一定比自己少。(注意每个人成绩都不同)  当给出要奖励的同学数N,及N名同学的成绩及排序位置,请你按照规则帮助老师计算出最少需要奖励多少支铅笔。  例如:当N=3,3名同学的成绩分别为:91,92,94  如果3名同学的排序为:91,94,92,最少需要奖励4支铅笔(成绩为91的同学1支,成绩为94的同学2支, 成绩为92的同学1支);  如果3名同学的排序为:91,92,94,最少需要奖励6支铅笔(成绩为91的同学1支,成绩为92的同学2支, 成绩为94的同学3支)。   输入描述:   第一行输入一个正整数N,N表示要奖励的同学数   第二行输入N个正整数,每个正整数表示一名同学的成绩(成绩各不相同),正整数之间以一个英文逗号隔 开,正整数的顺序即代表学生的排序   输出描述:   输出一个整数,表示N名同学最少需要奖励的铅笔数  样例输入:  3   91,94,92   样例输出:   4代码:

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

N=int(input())S=list(map(int,input().split(',')))rst=[0]*Nfor i in range(1,N):    if S[i]>S[i-1]:        rst[i]=rst[i-1]+1    else:        rst[i]=rst[i-1]-1
print(sum(rst)-(min(rst)-1)*N)

解说:如果知道第一个同学的笔数,通过推算就可以知道所有人的笔数,但第一个同学的笔数是不确定的。不过我们发现,作为纯数学考察,不管第一个数是多少,他们的相对差是不变的。因此可以假定一个数,推算所有的数后平移到最小值是1.

编程题5:  小蓝在玩翻卡片游戏,每张卡片一面写着大写字母“A”,另一面写着大写字母“B”。首先将卡片排成 一个N*N的矩阵。有的卡片是A面朝上,有的卡片是B面朝上。   现给定N的值,及N*N矩阵中每张卡片的状态,请你帮助小蓝挑选一张B面的卡,翻转成A面,使得翻转 后的上、下、左、右四个方向相连的A面卡片最多,并将相连最多的卡片数量输出。   例如:N=3,3*3的矩阵中的卡片状态如下:   选择红框内那张B面卡片,翻转为A面,可以使翻转后四个方向相连的A面卡片最多,为5张。   输入描述:   第一行输入一个正整数N(2≤N≤50),表示矩阵的行数和列数   第二行开始输入N行,每行输入N个字符(‘A’或者‘B’),表示矩阵中卡片状态,字符之间以一个 英文逗号隔开   输出描述:   输出一个整数,表示翻转后矩阵中上、下、左、右四个方向相连的最多A面卡片张数   样例输入:   3   A,B,B    A,B,A   B,A,B   样例输出:   5代码:

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

N=int(input())lst=[input().split(',') for i in range(N)]rst=[]def next(i,j):    find(i-1,j)    find(i+1,j)    find(i,j-1)    find(i,j+1)
def find(i,j):    if i<0 or i>=N or j<0 or j>=N:        return    if lst[i][j]=="A":        rst.append((i,j))        lst[i][j]="B"        next(i,j)count=0for i in range(N):    for j in range(N):        if lst[i][j]=="B":            next(i,j)            s=len(rst)+1            if s>count:                count=s            if s>1:                for idx in rst:                    lst[idx[0]][idx[1]]="A"                rst.clear()
print(count)

解说:用循环遍历所有的“B”,用递归检查每一个“B”上下左右“A”的数量,检查过程中改变“A”对象状态为“B”后加入结果列表中,结束每次递归后恢复结果列表所有对象的状态为“A”,清空结果列表。

编程题6:  给出一排黑色带数字的小球(数字为0到9),和一排白色带数字的小球(数字为0到9),现从两排小球 中一共选取K个小球排成一排。   要求:   1)选出的黑色小球顺序要和原来顺序一致;  2)选出的白色小球顺序要和原来顺序一致;   在满足以上要求的情况下,使得K个小球排成新的一排组成的数字最大    例如:黑色小球的原顺序为:Ž  白色小球的原顺序为: †‚„  K为3;   从两排小球中共选取3个小球,排成†„。可以组成的最大数字为654。   输入描述:   第一行输入一组正整数,代表黑色小球,每个正整数范围为0到9,正整数之间以一个英文逗号隔开   第二行输入一组正整数,代表白色小球,每个正整数范围为0到9,正整数之间以一个英文逗号隔开   第三行输入一个正整数K(K小于等于所有小球的总数),表示从所有小球中共选取K个小球   输出描述:   输出一个整数,表示按照要求选取K个小球后,组成的最大数字   样例输入:   2,5,3   6,2,4,1   3   样例输出:   654代码:

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

iptlsb= input().split(',')iptlsw= input().split(',')K=int(input())lst= [[1,int(iptlsb[i]),i] for i in range(len(iptlsb))] + [[2,int(iptlsw[i]),i] for i in range(len(iptlsw))]lst.sort(key=lambda x:x[1], reverse=True)rst=[]def find(index, ls):    if len(rst)==K:        return True    if index==len(ls):        return False    if checkBeforeResult(index, ls):        return find(index+1, ls)    rst.append(ls[index])    return find(index+1, ls)
def checkBeforeResult(index, ls):    if len(rst)==0:        return False    a=ls[index]    for t in rst:        if t[0]==a[0] and t[2]>a[2]:            return True    return False
for i in range(len(lst)):    rst.append(lst[i])    if find(0, lst[:i]+lst[i+1:]):        print(''.join(map(str,[i[1] for i in rst])))        break    else:        rst.clear()

解说:  如果每一次都是取两个列表混在一起的最大值,那么这个数就是最大的数(减少限制条件是获得解题思路的重要方法!)。但是由于要保持顺序,取最大的值可能造成后续的元素不够,这样就不得不舍而求次,直到后续有足够元素为止。  每一个数除了值的大小外,还有处于哪个列表和在列表中的位置,因此我们不能把它作为一个数来考虑,而应该作为数据结构的元素——节点。对象化编程思想往往能够把复杂的问题简单化,因为对象可以保持状态属性。

  每一个节点需要保留三个值——列表号、数值和位置。本文为了照顾没有掌握使用类的学生,使用一个三元素列表作为节点,依次为源列表号、数值和下标。合并两个列表的节点为一个节点,然后根据节点的值倒叙排序。

· 

· 

lst= [[1,int(iptlsb[i]),i] for i in range(len(iptlsb))] + [[2,int(iptlsw[i]),i] for i in range(len(iptlsw))]lst.sort(key=lambda x:x[1], reverse=True)

  从排好序的混合列表中按顺序取出一个节点放入结果列表中,剩下的混合列表递归获取最大的K-1位数——作为一个方案。如果由于条件限制无法完成,方案返回False,清理结果列表进入下一个方案的检查,最后必然有一个方案返回True。

· 

· 

· 

· 

· 

· 

· 

for i in range(len(lst)):    rst.append(lst[i])    if find(0, lst[:i]+lst[i+1:]):        print(''.join(map(str,[i[1] for i in rst])))        break    else:        rst.clear()

  递归函数find(开始下标,取出了方案节点的混合列表)需要完成下面的任务:首先判定结果是否已经达到K个,如果是就返回True;然后检查下标是否越界,如果是就返回False;第三检查当前下标的节点是否在结果集的前面,如果是就下推一个下标,递归调用;最后把该下标的节点加入结果列表,同样下推一个下标,递归调用。

· 

· 

· 

· 

· 

· 

· 

· 

· 

def find(index, ls):    if len(rst)==K:        return True    if index==len(ls):        return False    if checkBeforeResult(index, ls):        return find(index+1, ls)    rst.append(ls[index])    return find(index+1, ls)

  函数checkBeforeResult(当前下标,取出了方案节点的混合列表)检查当前节点是否在结果列表中任一个节点的前面。

· 

· 

· 

· 

· 

· 

· 

· 

def checkBeforeResult(index, ls):    if len(rst)==0:        return False    a=ls[index]    for t in rst:        if t[0]==a[0] and t[2]>a[2]:            return True    return False