第十二届蓝桥杯python大学A组


A:卡片

问题描述

小蓝有很多数字卡片,每张卡片上都是数字 0到 9。 小蓝准备用这些卡片来拼一些数,他想从 1 开始拼出正整数,每拼一个, 就保存起来,卡片就不能用来拼其它数了。 小蓝想知道自己能从 1 拼到多少。
例如,当小蓝有 30 张卡片,其中 0 到 9 各 3 张,则小蓝可以拼出 1 到 10, 但是拼 11 时卡片 1 已经只有一张了,不够拼出 11。 现在小蓝手里有 0 到 9 的卡片各 2021 张,共 20210 张,请问小蓝可以从 1 拼到多少?

解法一

解题思路

可以使用字典d统计0~9还有几张,i从1开始,统计i中元素出现个数,在字典d中,对应减去元素个数,当d.values()出现0时停止并返回i-1

python代码

#答案3181
d = {}
for i in range(10):
    d[i] = 2021
i = 0
flag = 1
while True:
    i += 1
    for j in str(i):
        tmp = int(j)
        if d[tmp] < 1:
            flag = 0
        else:
            d[tmp] -= 1
    if flag == 0:
        break
ans = i - 1
print(ans)

解法二

解题思路

因为是从1开始的使用卡片1毕然先消耗掉,从i = 1开始,统计“1”出现次数为count,当count==2021时返回i

python代码

#答案3181
i = 0
count = 0
while True:
    i += 1
    count += str(i).count("1")
    if count == 2021:
        print(i)
        break

B:直线

问题描述

在平面直角坐标系中,两点可以确定一条直线。如果有多点在一条直线上,那么这些点中任意两点确定的直线是同一条。
给定平面上 2 × 3 个整点 {(x, y)|0 ≤ x < 2, 0 ≤ y < 3, x ∈ Z, y ∈ Z},即横坐标是 0 到 1 (包含 0 和 1) 之间的整数、纵坐标是 0 到 2 (包含 0 和 2) 之间的整数的点。这些点一共确定了 11 条不同的直线。
给定平面上 20 × 21 个整点 {(x, y)|0 ≤ x < 20, 0 ≤ y < 21, x ∈ Z, y ∈ Z},即横坐标是 0 到 19 (包含 0 和 19) 之间的整数、纵坐标是 0 到 20 (包含 0 和 20) 之间的整数的点。请问这些点一共确定了多少条不同的直线。

解法一

解题思路

先将所有点存放在数字point中,在用集合liner储存直线的k,b。计算出每两个点的k,b放入liner,统计liner的长度就是直线条数。

python代码

#答案40257
point = []
for x in range(20):
    for y in range(21):
        point.append((x,y))
#ax+by+c=0
liner = set()
n = len(point)
for i in range(n-1):
    x1,y1=point[i][0],point[i][1]
    for j in range(i+1,n):
        x2,y2=point[j][0],point[j][1]
        if x1==x2:
            k = float('inf')
            b = x1
        else:
            k = (y2-y1)/(x2-x1)
            b = (x2*y1-x1*y2)/(x2-x1)
        if (k,b) not in liner:
            liner.add((k,b))
print(len(liner))

C:货物摆放

问题描述

小蓝有一个超大的仓库,可以摆放很多货物。

现在,小蓝有 n nn 箱货物要摆放在仓库,每箱货物都是规则的正方体。小蓝规定了长、宽、高三个互相垂直的方向,每箱货物的边都必须严格平行于长、宽、高。

小蓝希望所有的货物最终摆成一个大的长方体。即在长、宽、高的方向上分别堆 L LL、W WW、H HH 的货物,满足 n = L × W × H n = L \times W \times Hn=L×W×H。

给定 n nn,请问有多少种堆放货物的方案满足要求。

例如,当 n = 4 n = 4n=4 时,有以下 6 66 种方案:1 × 1 × 4 、 1 × 2 × 2 、 1 × 4 × 1 、 2 × 1 × 2 、 2 × 2 × 1 、 4 × 1 × 1 1×1×4、1×2×2、1×4×1、2×1×2、2 × 2 × 1、4 × 1 × 11×1×4、1×2×2、1×4×1、2×1×2、2×2×1、4×1×1

请问,当 n = 2021041820210418 n = 2021041820210418n=2021041820210418 (注意有 16 1616 位数字)时,总共有多少种方案?

解法一

解题思路

先求出n的所有约数储存在数字nums中,那么长和宽必定在数值nums中,两次遍历nums,当n%(长*宽)== 0时,ans+=1

python代码

#答案2430
import math
n = 2021041820210418
num = int(math.sqrt(n))
nums = [] #存放n的所有约数
for i in range(1,num+1):
    if n%i == 0:
        if i not in nums:
            nums.append(i)
        if n//i not in nums:
            nums.append(n//i)
nums.sort()
ans = 0
for i in range(len(nums)): #i表示长
    for j in range(len(nums)): #j表示宽
        if n%(nums[i]*nums[j]) == 0:
            ans += 1
print(ans)

D:路径

问题描述

小蓝学习了最短路径之后特别高兴,他定义了一个特别的图,希望找到图中的最短路径。小蓝的图由 2021 个结点组成,依次编号 1 至 2021。
对于两个不同的结点 a, b,如果 a 和 b 的差的绝对值大于 21,则两个结点之间没有边相连;如果 a 和 b 的差的绝对值小于等于 21,则两个点之间有一条长度为 a 和 b 的最小公倍数的无向边连。
例如:结点 1 和结点 23 之间没有边相连;结点 3 和结点 24 之间有一条无向边,长度为 24;结点 15 和结点 25 之间有一条无向边,长度为 75。
请计算,结点 1 和结点 2021 之间的最短路径长度是多少。
提示:建议使用计算机编程解决问题。

解法一

解题思路

定义数组dp = [0]*2022,dp[i]表示从节点1到节点i的最短路径长度,当 i < 22时,dp[i] = min(节点1 到节点 i-21~ i-1的最短路径距离 + 节点i-21~i-1 到 节点 i 的最短路径)
当i > 22时
dp[i] = 节点1 到 节点 i 的最短路径

python代码

#答案10266837
def gcd(a,b):  #求最大公因数
    while b > 0:
        a,b = b,a%b
    return a
def lcm(a,b): #求最大公倍数
    return a*b/gcd(a,b)
dp = [0]*2022
for i in range(2,2022):
    Min = float('inf')
    if i - 21 > 0:  #大于21时从i-21开始
        for j in range(i-21,i):
            #print(i,j,Min)
            Min = min(Min,lcm(j,i) + dp[j])
    else:
        for j in range(1,i):
            Min = min(Min,lcm(j,i) + dp[j])
    dp[i] = int(Min)
print(dp[-1])

E:回路计算

问题描述

蓝桥学院由21栋教学楼组成,教学楼编号1到21。对于两栋教学楼a和b,当a和b互质时,a和b之间有一条走廊直接相连,两个方向皆可通行,否则没有直接连接的走廊。

小蓝现在第一栋教学楼,他想要访问每栋教学楼正好一次,最终回到第一栋教学楼(即走一条哈密尔顿回路),请问他有多少种不同的访问方案?两个访问方案不同是指存在某个i,小蓝在两个访问方法中访问完教学楼i后访问了不同的教学楼。

解法一

解题思路

#答案881012367360
from math import gcd
n = int(input())
m = 1 << n
dp = [[0 for j in range(n)] for i in range(m)]
load = [[False for j in range(n)] for i in range(n)] 
for i in range(1, n + 1):
    for j in range(1, n + 1):
        if gcd(i, j) == 1:
            load[i - 1][j - 1] = True
dp[1][0] = 1
for i in range(1, m): 
    for j in range(n):
        if i >> j & 1: 
            for k in range(n): 
                if i - (1 << j) >> k & 1 and load[k][j]:  
                    dp[i][j] += dp[i - (1 << j)][k]
print(sum(dp[m - 1]) - dp[m - 1][0])

E:时间显示

问题描述

小蓝要和朋友合作开发一个时间显示的网站。在服务器上,朋友已经获取了当前的时间,用一个整数表示,值为从 1970 年 1 月 1 日 00:00:00 到当前时刻经过的毫秒数。

现在,小蓝要在客户端显示出这个时间。小蓝不用显示出年月日,只需要显示出时分秒即可,毫秒也不用显示,直接舍去即可。给定一个用整数表示的时间,请将这个时间对应的时分秒输出。

【输入格式】

输入一行包含一个整数,表示时间。

【输出格式】

输出时分秒表示的当前时间,格式形如 HH:MM:SS,其中 HH 表示时,值为 0 到 23,MM 表示分,值为 0 到 59,SS 表示秒,值为 0 到 59。时、分、秒不足两位时补前导 0。

【样例输入 1】

46800999

【样例输出 1】

13:00:00

【样例输入 2】

1618708103123

解法一

解题思路

import time
n = int(input())

#内置模块方法
print(time.asctime(time.gmtime(n//1000))[11:19])

#底层算法方法
n //= 1000 #将毫秒转换为秒
n %= 24*60*60 #最简一天过了多少秒
h =  n//(60*60)
m = n//60 - h*60
s = n%60
print('{:02d}:{:02d}:{:02d}'.format(h,m,s))

F:杨辉三角形

问题描述

在这里插入图片描述

解法一

解题思路

杨辉三角第n行第m个数可以表示为 C(m-1,n-1) = [(n-1)(n-2)(n-m+1)]/[(m-1)(m-2)*…*1]

def C(m,n): #求组合公式
    up = down = 1
    for i in range(n-m+1,n+1):
        up *= i
    for j in range(1,m+1):
        down *= j
    return up//down
if __name__ == "__main__":
    n = 6
    i = 1
    while True:
        flag = 0
        for j in range(1,i+1):
            if C(j-1,i-1) == n:
                flag = 1
                break
        if flag == 1:
            break
        i += 1
    ans = int((i**2-i)/2+j)
    print(ans)

G:左孩子右兄弟

题目描述

在这里插入图片描述
在这里插入图片描述

解法一

解题思路

定义一个树节点类,再初始化结点。
定义一个递归函数,求树的最大高度,最后遍历即可。
一步步转化,求二叉树最高高度->孩子结点个数

python代码

class Node():
    def __init__(self, val):
        self.val = val  #节点值
        self.children = []  #子节点
def maxhighte(n:Node):
    if len(n.children) == 0: #无孩子,高度为0
        return 0
    return len(n.children) + max(maxhighte(tree[x]) for x in n.children)
if __name__ == "__main__":
    tree = [None,Node(0)] # 初始化树
    n = int(input(5))
    for i in range(2,n+1):
        m = int(input())
        tree.append(Node(m))
        tree[m].children.append(i)
    ans = maxhighte(tree[1])
    print(ans)

解法一

解题思路

用二维数组来储存树
问题的关键在于 树的高度 = 根节点的子节点数 + 最高子树高度

python代码

#二维列表发
def dfs(t):
    if len(a[t]) == 0:
        return 0
    return len(a[t]) + max(dfs(x) for x in a[t])
a = [[] for _ in range(100001)] #测试数据最大为十万
n = int(input())
for child in range(2,n+1):
    fu = int(input())
    a[fu].append(child)
print(dfs(1))

I:异或数列

问题描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

解法一

解题思路

由题意可知Xi的位数不超过20位,我们可以将每一位的1的个数统计出来
1)当平局时A = B,A^B = 0 => 0^0^X1^X2.....X^n = 0即X1^X2.....X^n = 0时为平局
2)当最高位1的个数为奇数时且n为奇数时先手胜
3)当最高位1的个数为奇数时且n为偶数时后手胜

python代码

def per(nums,x): #统计每一位上1的个数
    for i in range(len(nums)):
        tmp = nums[i]
        cnt = 0
        while tmp:
            x[cnt] += tmp&1
            tmp = tmp >> 1
            cnt += 1
def solution(nums,x): #判断胜负
    ans = 0
    for i in nums:
        ans = ans ^ i
    if ans == 0:
        return ans
    for i in range(19,-1,-1):
        if x[i] == 1:
            ans = 1
            break
        else:
            if x[i]%2 == 1:
                if n%2 == 1:
                    ans = 1
                    break
                else:
                    ans = -1
                    break
    return ans
if __name__ == "__main__":
    N = int(input())
    i = 0
    ans = []
    while i < N:
        s = list(map(int,input().split(" ")))
        n = s[0]
        nums = s[1:]
        i += 1
        x = [0]*20
        per(nums,x)
        ans.append(solution(nums,x))
    print(ans)

J:括号序列

问题描述

在这里插入图片描述
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值