【蓝桥杯】国奖学长带你复盘第十三届蓝桥杯模拟赛

第十三届蓝桥杯模拟赛第二期python组个人题解

‍ 作者简介:大家好,我是可可卷,在十二届蓝桥杯中侥幸获得国家三等奖。自知实力有限,代码不足之处还请各位大佬多多批评指正~
主攻领域:【python算法】【数据分析】【数学建模】【机器学习】【深度学习】【数据可视化】
个人主页:可可卷的博客

【蓝桥杯】国奖学长带你复盘第十三届蓝桥杯模拟赛_第1张图片

文章目录

  • 第十三届蓝桥杯模拟赛第二期python组个人题解
    • 题目1
    • 题目2
    • 题目3
    • 题目4
    • 题目5
    • 题目6
    • 题目7
    • 题目8
    • 题目9
    • 题目10
    • 经验之谈

题目1

小蓝的IP地址为 192.168.*.21,其中 * 是一个数字,请问这个数字最大可能是多少 ?

答案:255

题解:计算机网络的内容,IP地址以8位二进制表示一个位,所以范围是【0,2^8-1】,因此最大值为255

题目2

如果一个整数 g 能同时整除整数 A 和 B,则称 g 是 A 和 B 的公约数。例如:43 是 86 和 2021 的公约数。
请问在 1(含) 到 2021(含) 中,有多少个数与 2021 存在大于 1 的公约数。请注意 2021 和 2021 有大于 1 的公约数,因此在计算的时候要算一个。

答案:89

题解:

先给大家二份计算最大公约数的代码:

# 迭代写法
def gcd(a,b):
    while b:
        a,b=b,a%b
    return a
    
# 递归写法
def gcd(a,b):
    if not a%b:return b
    return gcd(b,a%b)

然后计算与 2021 存在大于 1 的公约数的【数】的个数

res = 1
for i in range(1, 2021):
    if gcd(i, 2021) > 1:
        res += 1

print(res)

注意res初值为1,下面这份代码也是等价的

res = 0
for i in range(1, 2022):
    if gcd(i, 2021) > 1:
        res += 1

print(res)

题目3

2021 是一个非常特殊的数,它可以表示成两个非负整数的平方差,2021 = 45 * 45 - 2 * 2。
2025 也是同样特殊的数,它可以表示成 2025 = 45 * 45 - 0 * 0。
请问,在 1 到 2021 中有多少个这样的数?
请注意,有的数有多种表示方法,例如 9 = 3 * 3 - 0 * 0 = 5 * 5 - 4 * 4,在算答案时只算一次。

答案:1516

题解:记住3个点

  • 平方差公式:a^2 - b^2 = (a+b)(a-b)

  • 确定内层循环范围:b

  • 确定外层循环范围:b=a-1时取得最小正数,此时(a+b)(a-b)=(2a-1),令2a-1=2021,得到a的上限1011

代码:

nums=[0]*2022
for i in range(1,1012):
    for j in range(i):
        tmp=i*i-j*j
        if tmp<=2021:nums[tmp]=1
res=sum(nums)
print(res)

题目4

小蓝要用01串来表达一段文字,这段文字包含 a, b, c, d, e, f 共 6 个字母,每个字母出现的次数依次为:a 出现 10 次,b 出现 20 次,c 出现 3 次,d 出现 4 次,e 出现 18 次,f 出现 50 次。
 小蓝准备分别对每个字母使用确定的01串来表示,不同字母的01串长度可以不相同。
 在表示文字时,将每个字母对应的01串直接连接起来组成最终的01串。为了能够正常还原出文字,小蓝的编码必须是前缀码,即任何一个字符对应的01串都不能是另一个字符对应的01串的前缀。
 例如,以下是一个有效的编码:
 a: 000
 b: 111
 c: 01
 d: 001
 e: 110
 f: 100
 其中 c 的长度为 2,其它字母的编码长度为 3,这种方式表示这段文字需要的总长度为:103+203+32+43+183+503=312。
 上面的编码显然不是最优的,将上面的 f 的编码改为 10,仍然满足条件,但是总长度为 262,要短 50。
 要想编码后的总长度尽量小,应当让出现次数多的字符对应的编码短,出现次数少的字符对应的编码长。
 请问,在最优情况下,编码后的总长度最少是多少?

答案:219

题解:哈夫曼编码,作图如下
【蓝桥杯】国奖学长带你复盘第十三届蓝桥杯模拟赛_第2张图片

按左树为0,右树为1编码:
c: 3 11000
d: 4 11001
a: 10 1101
e: 18 111
b: 20 10
f: 50 0

5*3+5*4+4*10+3*18+2*20+1*50=219

题目5

下面的矩阵中包含 ABCDEF 六种字符,请问出现最多的字符出现了几次?
 FFEEFEAAECFFBDBFBCDA
 DACDEEDCCFFAFADEFBBA
 FDCDDCDBFEFCEDDBFDBE
 EFCAAEECEECDCDECADDC
 DFAEACECFEADCBFECADF
 DFBAAADCFAFFCEADFDDA
 EAFAFFDEFECEDEEEDFBD
 BFDDFFBCFACECEDCAFAF
 EFAFCDBDCCBCCEADADAE
 BAFBACACBFCBABFDAFBE
 FCFDCFBCEDCEAFBCDBDD
 BDEFCAAAACCFFCBBAAEE
 CFEFCFDEEDCACDACECFF
 BAAAFACDBFFAEFFCCCDB
 FADDDBEBCBEEDDECFAFF
 CDEAFBCBBCBAEDFDBEBB
 BBABBFDECBCEFAABCBCF
 FBDBACCFFABEAEBEACBB
 DCBCCFADDCACFDEDECCC
 BFAFCBFECAACAFBCFBAF

答案:78

题解:哈希表,或者用Counter

from collections import Counter
s = "FFEEFEAAECFFBDBFBCDA\
 DACDEEDCCFFAFADEFBBA\
 FDCDDCDBFEFCEDDBFDBE\
 EFCAAEECEECDCDECADDC\
 DFAEACECFEADCBFECADF\
 DFBAAADCFAFFCEADFDDA\
 EAFAFFDEFECEDEEEDFBD\
 BFDDFFBCFACECEDCAFAF\
 EFAFCDBDCCBCCEADADAE\
 BAFBACACBFCBABFDAFBE\
 FCFDCFBCEDCEAFBCDBDD\
 BDEFCAAAACCFFCBBAAEE\
 CFEFCFDEEDCACDACECFF\
 BAAAFACDBFFAEFFCCCDB\
 FADDDBEBCBEEDDECFAFF\
 CDEAFBCBBCBAEDFDBEBB\
 BBABBFDECBCEFAABCBCF\
 FBDBACCFFABEAEBEACBB\
 DCBCCFADDCACFDEDECCC\
 BFAFCBFECAACAFBCFBAF\\"

cnt=Counter(s)
print(cnt.most_common(1))

控制台显示: [('F', 78)]

题目6

小蓝要到店里买铅笔。
铅笔必须一整盒一整盒买,一整盒 12 支,价格 p 元。
小蓝至少要买 t 支铅笔,请问他最少花多少钱?
输入格式
输入一行包含两个整数 p、t,用一个空格分隔。
输出格式
输出一行包含一个整数,表示答案。
样例输入
5 30
样例输出
15
样例说明
小蓝至少要买3盒才能保证买到30支铅笔,总共花费 15 元。
评测用例规模与约定
对于所有评测用例,1 <= p <= 100,1 <= t <= 10000。

题解:取整

代码

p, t = map(int, input().split())
n = t // 12
if t % 12 != 0:
    n += 1
print(n * p)

题目7

给定一个三角形的三条边的长度 a, b, c,请问这个三角形是不是一个直角三角形。
输入格式
输入一行包含三个整数 a, b, c,表示三角形三边的长度,相邻整数之间用一个空格分隔。
输出格式
如果是直角三角形,输出“YES”(全大写),否则输出“NO”(全大写)。
样例输入
3 4 5
样例输出
YES
样例输入
4 5 4
样例输出
NO
评测用例规模与约定
对于所有评测用例,1 <= a, b, c <= 1000。

题解:先排序,再判断最短两边a、b与斜边c是否能构成直角三角形

代码:

def check(a, b, c):
    a,b,c=sorted([a,b,c])
    return a * a + b * b == c * c

a, b, c = map(int, input().split())
if check(a, b, c):
    print("YES")
else:
    print("NO")

题目8

n 个小朋友正在做一个游戏,每个人要分享一个自己的小秘密。
每个小朋友都有一个 1 到 n 的编号,编号不重复。
为了让这个游戏更有趣,老师给每个小朋友发了一张卡片,上面有一个 1 到 n 的数字,每个数字正好出现一次。
每个小朋友都将自己的秘密写在纸上,然后根据老师发的卡片上的数字将秘密传递给对应编号的小朋友。如果老师发给自己的数字正好是自己的编号,这个秘密就留在自己手里。
小朋友们拿到其他人的秘密后会记下这个秘密,老师会再指挥所有小朋友将手中的秘密继续传递,仍然根据老师发的卡片上的数字将秘密传递给对应编号的小朋友。
这样不断重复 n 次。
现在,每个小朋友都记下了很多个秘密。
老师现在想找一些小朋友,能说出所有秘密,请问老师最少要找几个小朋友?
输入格式
输入的第一行包含一个整数 n。
第二行包含 n 个整数 a[1], a[2], …, a[n],相邻的整数间用空格分隔,分别表示编号 1 到 n 的小朋友收到的数字。
输出格式
输出一行包含一个整数,表示答案。
样例输入
6
2 1 3 5 6 4
样例输出
3
样例说明
最终小朋友 1, 2 互相知道了对方的秘密,小朋友 3 只知道自己的秘密,小朋友 4, 5, 6 互相知道了对方的秘密。
至少要找 3 个小朋友才能说出所有秘密。
评测用例规模与约定
对于 30% 的评测用例,2 <= n <= 30。
对于 60% 的评测用例,2 <= n <= 1000。
对于所有评测用例,2 <= n <= 100000。

题解:构造并查集,判断最终有几个连通分支(可以看下我的并查集板子)

代码:

f={}
def find(x):
    f.setdefault(x,x)
    if x!=f[x]:
        f[x]=find(f[x])
    return f[x]

def union(x,y):
    f[find(x)]=f[find(y)]


n = int(input())
nums = list(map(int, input().split()))
for i,v in enumerate(nums):
    union(i+1,v)

for k in f.keys():
    f[k] = find(f[k])
res=len(set(f.values()))
print(res)

题目9

一个 1 到 n 的排列被称为半递增序列,是指排列中的奇数位置上的值单调递增,偶数位置上的值也单调递增。
例如:(1, 2, 4, 3, 5, 7, 6, 8, 9) 是一个半递增序列,因为它的奇数位置上的值是 1, 4, 5, 6, 9,单调递增,偶数位置上的值是 2, 3, 7, 8,也是单调递增。
请问,1 到 n 的排列中有多少个半递增序列?
输入格式
输入一行包含一个正整数 n。
输出格式
输出一行包含一个整数,表示答案,答案可能很大,请输出答案除以 1000000007 的余数。
样例输入
5
样例输出
10
样例说明
有以下半递增序列:
 (1, 2, 3, 4, 5)
 (1, 2, 3, 5, 4)
 (1, 2, 4, 3, 5)
 (1, 3, 2, 4, 5)
 (1, 3, 2, 5, 4)
 (1, 4, 2, 5, 3)
 (2, 1, 3, 4, 5)
 (2, 1, 3, 5, 4)
 (2, 1, 4, 3, 5)
 (3, 1, 4, 2, 5)
评测用例规模与约定
对于 50% 的评测用例,2 <= n <= 20。
对于所有评测用例,2 <= n <= 1000。

题解:动态规划,可以类比下杨辉三角

代码:

n = int(input())
k = n // 2
dp = [0] * 1001
mod = 1000000007
for i in range(1, n + 1):
    dp[0] = 1
    dp[i] = 1
    for j in range(i-1,0,-1):
        dp[j]=(dp[j]+dp[j-1])%mod
print(dp[k])

题目10

小蓝住在 LQ 城,今天他要去小乔家玩。
LQ 城可以看成是一个 n 行 m 列的一个方格图。
小蓝家住在第 1 行第 1 列,小乔家住在第 n 行第 m 列。
小蓝可以在方格图内走,他不愿意走到方格图外。
城市中有的地方是风景优美的公园,有的地方是熙熙攘攘的街道。小蓝很喜欢公园,不喜欢街道。他把方格图中的每一格都标注了一个属性,或者是喜欢的公园,标为1,或者是不喜欢的街道标为2。小蓝和小乔住的地方都标为了1。
小蓝每次只能从一个方格走到同一行或同一列的相邻方格。他想找到一条路径,使得不连续走两次标为 2 的街道,请问在此前提下他最少要经过几次街道?
输入格式
输入的第一行包含两个整数 n, m,用一个空格分隔。
接下来 n 行,每行一个长度为 m 第数字串,表示城市的标注。
输出格式
输出一行包含一个整数,表示答案。如果没有满足条件的方案,输出 -1。
样例输入
3 4
1121
1211
2211
样例输出
2
样例输入
3 4
1122
1221
2211
样例输出
-1
样例输入
5 6
112121
122221
221212
211122
111121
样例输出
5
评测用例规模与约定
对于 50% 的评测用例,2 <= n, m <= 20。
对于所有评测用例,2 <= n, m <= 300。

题解:DFS深度优先搜索,但是注意一定要剪枝,不然一定会导致迭代次数过多。关于深搜,可以看下我的DFS板子

代码:

n, m = map(int, input().split())
grid = []
for _ in range(0, n):
    tmp = [int(x) for x in input()]
    grid.append(tmp)

road=[(0,1),(0,-1),(-1,0),(1,0)] # 上下左右
inf=0x3f3f3f    # 无穷大
seen = [[0]*m for _ in range(0, n)]
temp = [[inf]*m for _ in range(0, n)]
res = [inf]     # 不能直接用res=inf记录,可以想想为什么

def dfs(x, y, step, t):
    if x == n - 1 and y == m - 1:
        res[0] = min(res[0],step)
        return

    if step < temp[x][y]:
        temp[x][y] = step
    else:  # 剪枝,非最优路径提前结束搜索
        return

    for dx,dy in road:
        tx,ty=x+dx,y+dy
        if tx in(-1,n) or ty in (-1,m):continue
        if seen[tx][ty]:continue

        if grid[tx][ty] == 2:
            if t == 1:continue  # 剪枝,遇到2次街道
            if step == res[0]:continue  # 剪枝,因为继续搜索得到的路径一定更大
            seen[tx][ty] = 1
            dfs(tx, ty, step + 1, 1)
            seen[tx][ty] = 0
        else:
            seen[tx][ty] = 1
            dfs(tx, ty, step, 0)
            seen[tx][ty] = 0

seen[0][0] = 1
dfs(0, 0, 0, 0)
if res[0] == inf:
    print(-1)
else:
    print(res[0])

经验之谈

  • 蓝桥杯与acm等竞赛相比,难度较低,题目多为暴力、思维和搜索,并且有骗分的可能,建议可以多总结下骗分技巧(bushi)。

  • 暴力写得好,动态规划再熟悉下,python省一就差不多,搜索和剪枝写得好,python国二也不是梦。

  • 起步建议做codeforces的div2的ab题,也可以结合力扣里相应的tag刷熟相应数据结构和算法技巧,如前缀和,并查集等,这里我也总结了一些板子

  • 书籍的话不推荐刘汝佳算法竞赛入门经典,可以看看挑战程序竞赛(白书)

  • 对于入门者来说,自己看书学可能会有一点点难度,这里推荐acwing,有蓝桥杯历年题可以提交评测,并且拿奖还可以返还学费(国奖全返哦~)

你可能感兴趣的:(数据结构与算法,蓝桥杯,算法,职场和发展,python,数据结构)