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

第一题:  提示信息:   平方是一种运算,比如:a 的平方表示 a×a。   例如:2 的平方为 4 (也就是 2*2 的积)   例如:4 的平方为 16 (也就是 4*4 的积)   编程实现:   输入一个正整数 n,将 1 到 n 之间所有正整数(包含 1 和 n)作为 Python字典的键,将正整数的平方作为对应键的值,组成 n 个键值对。输出 1 到 n 的所有键值对(格式要求:每个键值对之间以英文逗号隔开,输出的内容前后中间不能有空格及大括号)。   输入描述:输入一个正整数  输出描述:输出 1 到 n 的所有键值对(按照编程实现要求输出) 样例输入:5 样例输出:1:1,2:4,3:9,4:16,5:25代码

· 

· 

· 

· 

n = int(input())for i in range(1,n):    print("%d:%d" % (i,i**2), end=",")print("%d:%d" % (n,n**2))

第二题:

  提示信息: 

  假设给出一个数值 9876543201,直接看这个数字很难直观准确的读出来,为了准确快速的读出一个数字, 想请你编写一个读数系统。

数级

 

亿级

万级

个级

数位

...

...

亿位

千万位

百万位

十万位

万位

千位

百位

十位

个位

计数

单位

...

...

亿

千万

百万

十万

  中文读数规则:1.从高位读起,先读亿级,再读万级,最后读个级;2. 读亿级和万级时按读个级的方法来读,读完亿级后加上一个“亿”字,读完万级后加上一个“万”字;3. 每级末尾不管有几个 0 都不读, 每级中间和前面有一个或连续几个 0,都只读一个 0。后面的数级全0也不读,中间数级连续为0也只读一个0,不读数级单位。  编程实现:   输入一个小于一百亿的正整数 n(1≤n<10000000000),按照中文读写的规范转为汉语拼音字串,相邻的两个音节用一个空格符隔开。   例如:给定一个阿拉伯数字串“9876543201”   中文读写的规范:九十八亿七千六百五十四万三千二百零一   汉语拼音字串:jiu shi ba yi qi qian liu bai wu shi si wan san qian er bai ling yi  输入描述:   输入一个小于一百亿的正整数 n(1≤n<10000000000)   输出描述:   输出其对应汉语拼音字串,相邻的两个音节用一个空格符隔开   样例输入:  54321001   样例输出:   wu qian si bai san shi er wan yi qian ling yi代码:

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

n = int(input())#1位数读法def _1df(d):    if d == 0:        return 'ling'    elif d == 1:        return 'yi'    elif d == 2:        return 'er'    elif d == 3:        return 'san'    elif d == 4:        return 'si'    elif d == 5:        return 'wu'    elif d == 6:        return 'liu'    elif d == 7:        return 'qi'    elif d == 8:        return 'ba'    else:        return 'jiu'#加入位def _wdf(w):    if w == 0:        return 'qian'    elif w == 1:        return 'bai'    elif w == 2:        return 'shi'    else:        return None
#4位数读法def _4df(d):    if d == 0:        return None    ds = d//1000, (d % 1000)//100, (d % 100)//10, d % 10    start = 0    while ds[start] == 0:        start += 1    s0 = _1df(ds[start])    unit = _wdf(start)    if unit == None:        return s0    lst = []    lst.append(s0)    lst.append(unit)
    start += 1    s1 = _1df(ds[start])    unit = _wdf(start)    if unit == None:        if ds[start] > 0:            lst.append( s1)        return " ".join(lst)      if ds[start] == 0:        preZero = True    else:        lst.append(s1)        lst.append(unit)        preZero = False
    start += 1    s2 = _1df(ds[start])    unit = _wdf(start)    if unit == None:        if ds[start] > 0:            if preZero:                lst.append('ling')            lst.append( s2)        return " ".join(lst)      if ds[start] == 0:        preZero = True    else:        if preZero:            lst.append('ling')        lst.append(s2)        lst.append(unit)        preZero = False
    start += 1    if ds[start] > 0:        if preZero:            lst.append('ling')        lst.append(_1df(ds[start]))
    return " ".join(lst)  
y,w,g = n//100000000, (n % 100000000)//10000, n % 10000lst = []if y > 0:    lst.append(_4df(y))    lst.append('yi')
if w > 0:    lst.append(_4df(w))    lst.append('wan')    preZero = Falseelse:    if y > 0:        preZero = True    else:        preZero = False
if g > 0:    if preZero:        lst.append('ling')    lst.append(_4df(g))
print(" ".join(lst))    

解说:本题的难点是如何读0。  四位数读法函数_4df:  把每级数分为4个数字的列表:

· 

ds = d//1000, (d % 1000)//100, (d % 100)//10, d % 10

  定位到非0位:

· 

· 

· 

    start = 0    while ds[start] == 0:        start += 1

  读数第一位:

· 

s0 = _1df(ds[start])

  如果该数位无单位,则说明已到个位,返回。

· 

· 

· 

    unit = _wdf(start)    if unit == None:        return s0

  否则建列表,把该位读数和单位加进去:

· 

· 

· 

    lst = []    lst.append(s0)    lst.append(unit)

  读数第二位:

· 

· 

    start += 1    s1 = _1df(ds[start])

  如果该数位无单位,则说明已到个位,返回。

· 

· 

· 

· 

· 

    unit = _wdf(start)    if unit == None:        if ds[start] > 0:            lst.append( s1)        return " ".join(lst)

  如果该位数字为0,把读数状态preZero初始化为True:

· 

· 

    if ds[start] == 0:        preZero = True

  否则,把该数位的读数和单位都加进结果列表中,前导0初始化为False:

· 

· 

· 

· 

    else:        lst.append(s1)        lst.append(unit)        preZero = False

  读数第三位:

· 

· 

    start += 1    s2 = _1df(ds[start])

  如果该数位无单位,则说明已到个位,返回,如果前导0状态为True,在读数前加"ling"。

· 

· 

· 

· 

· 

· 

    if unit == None:        if ds[start] > 0:            if preZero:                lst.append('ling')            lst.append( s2)        return " ".join(lst)

  如果该位数字为0,把读数状态preZero初始化为True:

· 

· 

    if ds[start] == 0:        preZero = True

  否则,把该数位的读数和单位都加进结果列表中,前导0初始化为False:

· 

· 

· 

· 

· 

· 

    else:        if preZero:            lst.append('ling')        lst.append(s2)        lst.append(unit)        preZero = False

  读数第四位,如果非0,加入读数,在加入读数之前,检查是否是前导0,是就要加个‘ling’:

· 

· 

· 

· 

· 

    start += 1    if ds[start] > 0:        if preZero:            lst.append('ling')        lst.append(_1df(ds[start]))

  数级读数代码:  把原数分为3级:

· 

y,w,g = n//100000000, (n % 100000000)//10000, n % 10000

  判断与读数亿级,如果大于0,读数及加单位:

· 

· 

· 

· 

lst = []if y > 0:    lst.append(_4df(y))    lst.append('yi')

  判断与读数万级,如果万级大于0,读数后加单位,前导0置为False:

· 

· 

· 

· 

if w > 0:    lst.append(_4df(w))    lst.append('wan')    preZero = False

  否则,如果亿级大于0,前导0置为True:

· 

· 

· 

· 

· 

else:    if y > 0:        preZero = True    else:        preZero = False

  判断与读数个级,如果个级大于0,如果前导0为True,先加‘ling’,后加这个级的读数:

· 

· 

· 

· 

if g > 0:    if preZero:        lst.append('ling')    lst.append(_4df(g))

第三题:  编程实现:   约分是把分数化成最简分数的过程,约分后分数的值不变,且分子分母的最大公约数为1,若最终结果的分母为1,则直接用整数表示。   提示:两个以逗号分隔输入的整数,可以采用如下方法进行转换、分离:   str = input()   nums = eval(str)   输入:   输入两个正整数(以逗号分隔)分别作为分数的分子和分母   输出:   第一行显示输入的分数   第二行显示约分后的最简分数,若分母为1,直接用整数表示。   样例输入1:   27,30   样例输出1:   27/30   9/10   样例输入2:   36,6   样例输出2:   36/6  6代码:

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

nums = eval(input())#计算最大公约数,大的数减小的数直到相等def gys(num1,num2):    if num1 == num2:        return num1    if num1 > num2:        return gys(num1-num2, num2)    else:        return gys(num2-num1, num1)n = gys(nums[0],nums[1])num1 = nums[0] // nnum2 = nums[1] // nprint("/".join(map(str,nums)))if num2 == 1:    print(num1)else:    print("/".join([str(num1),str(num2)]))

解说:  本处采用连减求最大公约数,首先简单说一说它的数学原理。给定两个不相等正整数a和b,假设k是它们的最大共约数,则:  a = kp;  b = kq。  用kp和kq的大者减小者的差,然后小者与差构成新的一对同样操作,最终会得到一对相等的值k和k,就是最大公约数。  例如:12和18,18-12=6,12-6=6,得到6,6,所以6是最大公约数。  用递归函数gys实现求公约数,返回条件:

· 

· 

    if num1 == num2:        return num1

  递归过程:

· 

· 

· 

· 

    if num1 > num2:        return gys(num1-num2, num2)    else:        return gys(num2-num1, num1)

  方法二:分数对象自动约分,构建分数后输出分子和分母就可以了。下面是用分数模块实现的代码:

· 

· 

· 

· 

· 

· 

· 

· 

· 

from fractions import Fractionnum1,num2 = map(int, input().split(','))fr = Fraction(num1,num2)print("/".join([str(num1),str(num2)]))if fr.denominator == 1:    print(fr.numerator)else:    print(fr)

  方法三:暴力法。从小的那个数开始测试,首次遇到能整除2个数的因数就是最大公约数。代码如下:

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

nums = eval(input())def gys(num1,num2):    for i in range(min(num1,num2),0,-1):        if num1 % i == 0 and num2 % i == 0:            return i            n = gys(nums[0],nums[1])num1 = nums[0] // nnum2 = nums[1] // nprint("/".join(map(str,nums)))if num2 == 1:    print(num1)else:    print("/".join([str(num1),str(num2)]))

 

第四题:  提示信息:   杨辉三角形,是二项式系数在三角形中的一种几何排列。中国南宋数学家杨辉在 1261 年所著的《详解九章算法》一书有明确记载。欧洲数学家帕斯卡在 1654 年发现这一规律,所以又叫做帕斯卡三角形。其定义为:其顶端(第 1 行)是 1;第 2 行是两个 1;第 3 行是‘1,2,1’,中间的‘2’是其上方相邻的两个数字的和;依次类推,产生如下图 3 所示的杨辉三角形。

3 杨辉三角形

  编程实现:   对于任意输入的在 3~15 之间的正整数 n,请编程输出前 n 行数字、以及由其组成的杨辉三角形。   函数提示:

  print(‘{:<3}’.format(10)) 能够以 3 个字符宽度、左对齐的方式显示数字 10。 

  输入: 

  一个正整数 n(2 ≤ n ≤ 15): 

  输出: 

  由两部分组成。第一部分输出由 n 行数字组成的列表;第二部分输出 n 行数字组成的杨辉三角形。具体输出格式参考如下样例。 

  样例输入:(提示:以下    ”为背景的信息是程序输出内容) 

  请输入一个在 2~15 之间的正整数: 6 

  样例输出:

代码:

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

· 

n = int(input("请输入一个在2~15之间的正整数:"))#下推一行:前移一位后对应项目相加def down(ls):    L1 = ls+[0]    L2 = [0]+ls    L = []    for i in range(len(L1)):        L.append(L1[i]+L2[i])    return L#生成一行def createLine(ls):    s = [" "*(3*(n-len(ls)))]    for it in ls:        s.append('{:<6}'.format(it))    return "".join(s)    
lst = [1]allLst = []for i in range(n):    print(lst)    allLst.append(createLine(lst))    lst = down(lst)
print("\n".join(allLst))

解说:  杨辉三角形行之间的关系,实际是一行左移1位与没有移位的这一行对应项相加,就可以得到下一行(这种方法最适合笔算,编程与标准方法——相邻2项相加没有什么优势):

· 

· 

· 

· 

· 

· 

· 

def down(ls):    L1 = ls+[0]    L2 = [0]+ls    L = []    for i in range(len(L1)):        L.append(L1[i]+L2[i])    return L

  杨辉三角形本来是一个直角三角形,如果要打印出等腰三角形,那么每行就要后推½空档。本文一个数占6个字符,一半就是3个字符。生成一行打印字符串的代码如下:

· 

· 

· 

· 

· 

def createLine(ls):    s = [" "*(3*(n-len(ls)))]    for it in ls:        s.append('{:<6}'.format(it))    return "".join(s)

  用循环生成杨辉三角形,顺便打印每行的列表:

· 

· 

· 

· 

· 

· 

lst = [1]allLst = []for i in range(n):    print(lst)    allLst.append(createLine(lst))    lst = down(lst)