本次蓝桥杯国赛的题目,感觉质量比省赛时好了不少,题目难易适中,有难有易。不得不吐槽一下早上的打车经历,到考场10分钟左右的车程,愣是等车等了20分钟。
比赛超常发挥,我没想过我能把10道题全做出来。把自己的解题思路写在这里,也仅代表我个人理解得出的思路,不代表官方答案,欢迎大家交流,指正错误。
题目不太完整,没找到Python
A组的完整试题,就从C
A和C
B里找了些一样的题。后续再补充。少两个题目,只记得一个是二进制计 1 1 1,另一个就不记得了。
拿到全部题目了,更新一下。——2021.6.7
本题总分:5分
【问题描述】
小蓝家的网络带宽是 200 M b p s 200 Mbps 200Mbps,请问,使用小蓝家的网络理论上每秒钟最 多可以从网上下载多少 M B MB MB 的内容。
【思路分析】
这个题就比较简单了,签到题,Mbps/8
就是实际速度
【参考答案】
25
本题总分:5 分
【问题描述】
如果一个正整数只有 1 1 1 和它本身两个约数,则称为一个质数(又称素数)。
前几个质数是: 2 , 3 , 5 , 7 , 11 , 13 , 17 , 19 , 23 , 29 , 31 , 37 , . . . 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, ... 2,3,5,7,11,13,17,19,23,29,31,37,... 。
如果一个质数的所有十进制数位都是质数,我们称它为纯质数。例如: 2 , 3 , 5 , 7 , 23 , 37 2, 3, 5, 7, 23, 37 2,3,5,7,23,37 都是纯质数,而 11 , 13 , 17 , 19 , 29 , 31 11, 13, 17, 19, 29, 31 11,13,17,19,29,31 不是纯质数。当然 1 , 4 , 35 1, 4, 35 1,4,35 也不是纯质数。
请问,在 1 1 1 到 20210605 20210605 20210605 中,有多少个纯质数?
【思路分析】
这个题比较直观,首先判断[1、4、6、8、9、0]
在这个数里边,就一定不是纯质数。
def isPurePrime(n):
s = str(n)
for i in range(len(s)):
if s[i] == '0' or s[i] == '1' or s[i] == '4' or s[i] == '6' or s[i] == '8' or s[i] == '9':
return False
if isPrime(n):
return True
return False
然后如果都不在,再判断这个数是不是质数,例如22
def isPrime(n):
if n <= 3:
return n >= 2
if (n + 1) % 6 != 0 and (n - 1) % 6 != 0:
return False
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
return False
return True
最后循环跑一下结果就出来了
【参考答案】
1903
比赛时把0
忘了,心里默念 m m p mmp mmp。
本题总分:10 分
【问题描述】
如果一个日期中年月日的各位数字之和是完全平方数,则称为一个完全日期。
例如: 2021 2021 2021 年 6 6 6 月 5 5 5 日的各位数字之和为 2 + 0 + 2 + 1 + 6 + 5 = 16 2 + 0 + 2 + 1 + 6 + 5 = 16 2+0+2+1+6+5=16 ,而 16 16 16 是一个完全平方数,它是 4 4 4 的平方。所以 2021 2021 2021 年 6 6 6 月 5 5 5 日是一个完全日期。
例如: 2021 2021 2021 年 6 6 6 月 23 23 23 日的各位数字之和为 2 + 0 + 2 + 1 + 6 + 2 + 3 = 16 2 + 0 + 2 + 1 + 6 + 2 + 3 = 16 2+0+2+1+6+2+3=16,是一个完全平方数。所以 2021 2021 2021 年 6 6 6 月 23 23 23 日也是一个完全日期。
请问,从 2001 2001 2001 年 1 1 1 月 1 1 1 日到 2021 2021 2021 年 12 12 12 月 31 31 31 日中,一共有多少个完全日期?
【思路分析】
常规日期题,模拟日期操作然后判断即可。日期,最大 8 8 8 位数,且最大的和为2+0+1+9+1+2+3+1=19这里经过大佬指正,最大的和应为 2 + 0 + 1 + 9 + 1 + 2 + 2 + 9 = 26 2+0+1+9+1+2+2+9=26 2+0+1+9+1+2+2+9=26,所以可以提前算出来[1,4,9,16,25]
这几个数,然后直接判断即可,不必重复计算。
def wonderDate(year, month, day):
date = [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
year = list(map(int, list(str(year))))
month = list(map(int, list(str(month))))
day = list(map(int, list(str(day))))
return sum(year) + sum(month) + sum(day) in date
year, month, day, c = 2001, 1, 1, 0
while year < 2022:
if wonderDate(year, month, day):
c += 1
day += 1
if year in [2004, 2008, 2012, 2016, 2020] and month == 2 and day > 29:
day = 1
month += 1
elif month == 2 and day > 28:
day = 1
month += 1
elif month in [1, 3, 5, 7, 8, 10, 12] and day > 31:
day = 1
month += 1
elif month in [4, 6, 9, 11] and day > 30:
day = 1
month += 1
if month > 12:
month = 1
year += 1
print(c)
【参考答案】
977
本题总分:10 分
【问题描述】
对于一棵有根二叉树 T T T,小蓝定义这棵树中结点的权值 W ( T ) W(T) W(T) 如下:
空子树的权值为 0 0 0。
如果一个结点 v v v 有左子树 L L L, 右子树 R R R,分别有 C ( L ) C(L) C(L) 和 C ( R ) C(R) C(R) 个结点,则
W ( v ) = 1 + 2 W ( L ) + 3 W ( R ) + ( C ( L ) ) 2 C ( R ) 。 W(v) = 1 + 2W(L) + 3W(R) + (C(L))^2 C(R)。 W(v)=1+2W(L)+3W(R)+(C(L))2C(R)。
树的权值定义为树的根结点的权值。
小蓝想知道,对于一棵有 2021 2021 2021 个结点的二叉树,树的权值最小可能是多 少?
【问题分析】
这个题不太会做,蒙了一下,觉得应该是一棵完全二叉树,并且多余的部分肯定是在右侧,因为左边的子节点数量是平方。
然后开始模拟。
nodes = [[0],
[0,0],
[0,0,0,0]] # 这是模拟那棵2021个节点的树,太占地方就不放完了
for i in range(1024 - 998 + 1, len(nodes[9])): # 初始化底层状态
nodes[9][i] = 1
for i in range(8, -1, -1):
for j in range(len(nodes[i])):
# 根据公式计算,其中完全二叉树左下节点数量和右下节点数量 = 2**子节点层数-1
nodes[i][j] = 1 + 2 * nodes[i + 1][j * 2] + 3 * nodes[i + 1][j * 2 + 1] + ((2 ** (10 - i) - 1) ** 2) * (2 ** (10 - i) - 1)
for i in nodes:
print(i)
print(nodes[0][0])
写到这儿,又发现一个问题,这棵树左下节点不能直接按照 2 n − 1 − 1 2^{n-1}-1 2n−1−1 来算,又错了,,答案就不放了,这个思路可供也仅供参考。
时间限制: 1.0s 内存限制: 256.0MB 本题总分:15 分
【问题描述】
给定一个只包含大写字母和小写字母的字符串,请将其中所有的小写字母 转换成大写字母后将字符串输出。
【输入格式】
输入一行包含一个字符串。
【输出格式】
输出转换成大写后的字符串。
【样例输入 1】
LanQiao
【样例输出 1】
LANQIAO
【思路分析】
签到题
【代码】
print(input().upper())
时间限制: 1.0s 内存限制: 256.0MB 本题总分:15 分
【问题描述】
小蓝发现了一个有趣的数列,这个数列的前几项如下:
1 , 1 , 2 , 1 , 2 , 3 , 1 , 2 , 3 , 4 , . . 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, .. 1,1,2,1,2,3,1,2,3,4,..
小蓝发现,这个数列前 1 1 1 项是整数 1 1 1,接下来 2 2 2 项是整数 1 1 1 至 2 2 2,接下来 3 3 3 项是整数 1 1 1 至 3 3 3,接下来 4 4 4 项是整数 1 1 1 至 4 4 4,依次类推。
小蓝想知道,这个数列中,连续一段的和是多少。
【输入格式】
输入的第一行包含一个整数 T T T,表示询问的个数。
接下来 T T T 行,每行包含一组询问,其中第 i i i 行包含两个整数 l i l_i li 和 r i r_i ri,表示 询问数列中第 l i l_i li 个数到第 r i r_i ri 个数的和。
【输出格式】
输出 T T T 行,每行包含一个整数表示对应询问的答案。
【样例输入】
3
1 1
1 3
5 8
【样例输出】
1
4
8
【思路分析】
这个题我没找到啥太好的规律,就只能通过模拟的方式模拟数组,然后出区间和,通过判断最大值,降低一定的时间。估计超时不能拿满分。
【代码实现】
n = int(input())
l, r = [], []
for i in range(n):
s = input().split()
l.append(int(s[0]))
r.append(int(s[1]))
m = max(r)
m_c = m + 0
row = 1
while m_c > 0:
for i in range(row):
m_c -= 1
row += 1
row -= 1
ls = []
for i in range(1, row + 1):
for j in range(1, i + 1):
ls.append(j)
for i in range(n):
print(sum(ls[l[i] - 1:r[i]]))
时间限制: 1.0s 内存限制: 256.0MB 本题总分:20 分
【问题描述】
一片海域上有一些冰山,第 i i i 座冰山的体积为 V i V_i Vi。
随着气温的变化,冰山的体积可能增大或缩小。第 i i i 天,每座冰山的变化 量都是 X i X_i Xi。当 X i > 0 X_i > 0 Xi>0 时,所有冰山体积增加 X i X_i Xi;当 X i < 0 X_i < 0 Xi<0 时,所有冰山体积减 少 − X i −X_i −Xi;当 X i = 0 X_i = 0 Xi=0 时,所有冰山体积不变。
如果第 i i i 天某座冰山的体积变化后小于等于 0 0 0,则冰山会永远消失。
冰山有大小限制 k k k。如果第 i i i 天某座冰山 j j j 的体积变化后 V j V_j Vj 大于 k k k,则它 会分裂成一个体积为 k k k 的冰山和 V j − k V_j − k Vj−k 座体积为 1 1 1 的冰山。
第 i i i 天结束前(冰山增大、缩小、消失、分裂完成后),会漂来一座体积为 Y i Y_i Yi 的冰山( Y i = 0 Y_i = 0 Yi=0 表示没有冰山漂来)。
小蓝在连续的 m m m 天对这片海域进行了观察,并准确记录了冰山的变化。小 蓝想知道,每天结束时所有冰山的体积之和(包括新漂来的)是多少。
由于答案可能很大,请输出答案除以 998244353 998244353 998244353 的余数。
【输入格式】
输入的第一行包含三个整数 n , m , k n, m, k n,m,k分别表示初始时冰山的数量、观察的 天数以及冰山的大小限制。
第二行包含 n n n 个整数 V 1 , V 2 , . . . , V n V_1, V_2, ... , V_n V1,V2,...,Vn,表示初始时每座冰山的体积。
接下来 m m m 行描述观察的 m m m 天的冰山变化。其中第 i i i 行包含两个整数 X i , Y i X_i , Y_i Xi,Yi, 意义如前所述。
【输出格式】
输出 m m m 行,每行包含一个整数,分别对应每天结束时所有冰山的体积之和 除以 998244353 998244353 998244353 的余数。
【样例输入】
1 3 6
1
6 1
2 2
-1 1
【样例输出】
8
16
11
【样例说明】
在本样例说明中,用 [ a 1 , a 2 , . . . , a n ] [a_1, a_2, ... , a_n] [a1,a2,...,an] 来表示每座冰山的体积。
初始时的冰山为 [ 1 ] [1] [1]。
第 1 1 1 天结束时,有 3 3 3 座冰山: [ 1 , 1 , 6 ] [1, 1, 6] [1,1,6]。
第 2 2 2 天结束时,有 6 6 6 座冰山: [ 1 , 1 , 2 , 3 , 3 , 6 ] [1, 1, 2, 3, 3, 6] [1,1,2,3,3,6]。
第 3 3 3 天结束时,有 5 5 5 座冰山: [ 1 , 1 , 2 , 2 , 5 ] [1, 1, 2, 2, 5] [1,1,2,2,5]。
【思路分析】
这个题虽然看起来很长,但仔细读其实也不难,跟着步骤一步步去模拟就行了。但要注意避坑:
分裂的话,比如上限是6
,有个冰山是8
,不是分裂成[6,2]
,而是分解成[6,1,1]
。最后记得%998244353
这个题的数据量也比较大,可能跑不完。
【代码实现】
n, m, k = map(int, input().split()) # 冰山数量、观察天数、大小限制
ices = list(map(int, input().split())) # 每座冰山
for i in range(m):
x, y = map(int, input().split()) # X:冰山每天的变化量 Y: 结束时飘来的冰山
for i in range(len(ices)):
ices[i] += x
if x > 0: # 增加,要考虑分裂
for i in range(len(ices)):
if ices[i] > k:
for j in range(ices[i] - k):
ices.append(1)
ices[i] = k
else: # 减少,考虑消失
ices = list(filter(lambda x: x > 0, ices))
ices.append(y) # 飘来一座冰山
print(sum(ices) % 998244353)
时间限制: 1.0s 内存限制: 512.0MB 本题总分:20 分
【问题描述】
给定一个数列 A = ( a 1 , a 2 , . . . , a n ) A = (a_1, a_2, ... , a_n) A=(a1,a2,...,an),问有多少个区间 [ L , R ] [L, R] [L,R] 满足区间内元素 的乘积等于他们的和,即 a L ∗ a L + 1 . . . a R = a L + a L + 1 + . . . + a R a_L * a_{L+1} ... a_R = a_L + a_{L+1} + ... + a_R aL∗aL+1...aR=aL+aL+1+...+aR 。
【输入格式】
输入第一行包含一个整数 n n n,表示数列的长度。
第二行包含 n 个整数,依次表示数列中的数 a 1 , a 2 , . . . , a n a_1, a_2, ... , a_n a1,a2,...,an。
【输出格式】
输出仅一行,包含一个整数表示满足如上条件的区间的个数。
【样例输入】
4
1 3 2 2
【样例输出】
6
【样例解释】
符合条件的区间为 [ 1 , 1 ] , [ 1 , 3 ] , [ 2 , 2 ] , [ 3 , 3 ] , [ 3 , 4 ] , [ 4 , 4 ] [1, 1], [1, 3], [2, 2], [3, 3], [3, 4], [4, 4] [1,1],[1,3],[2,2],[3,3],[3,4],[4,4]。
【思路分析】
这个题,两层for
循环遍历一下就出来了,就是不知道能不能跑通所有测试点。。。
【代码实现】
n = int(input())
ls = list(map(int, input().split()))
c = 0
for i in range(n):
s = 0
cj = 1
for j in range(n - i - 1, n):
s += ls[j]
cj *= ls[j]
if s == cj:
c += 1
print(c)
时间限制: 1.0s 内存限制: 512.0MB 本题总分:25 分
【问题描述】
小蓝最近在学习二进制。他想知道 1 1 1 到 N N N 中有多少个数满足其二进制表示 中恰好有 K K K 个 1 1 1。你能帮助他吗?
【输入格式】
输入一行包含两个整数 N N N 和 K K K。
【输出格式】
输出一个整数表示答案。
【样例输入】
7 2
【样例输出】
3
【思路分析】
这个题乍一看也比较简单哈,第一遍做的时候秒出。
n, k = map(int, input().split())
c = 0
for i in range(1, n + 1):
if bin(i).count('1') == k:
c += 1
print(c)
后来做完全部的题还有1个多小时,我就开始检查,检查到这,想着好歹是个25分的题,不应该这么简单啊。然后看了下测试样例
仅仅到 2 ∗ 1 0 7 2*10^7 2∗107就很费劲了,1秒之内肯定是跑不完的,也就是按原程序估计最多拿40%的分数。于是在想办法优化这个算法。
首先,k
最大二进制的长度,就不用算了,肯定是 0 0 0,比如,7
是111
,但如果k=4
,那肯定就不用算了呀
其次,由于这是找有几个,跟大小并没有关系,例如从7
里边找2
个1
,7
是111
,找两个,那就是数学上的组合问题, C 3 2 C_3^2 C32。
C 5 3 = ( 5 ∗ 4 ∗ 3 ) / ( 3 ∗ 2 ∗ 1 ) C_5^3=(5*4*3)/(3*2*1) C53=(5∗4∗3)/(3∗2∗1)
对于不是 2 n − 1 2^n-1 2n−1的数字,拿12
举例,12=0b1100
,这时如果统计3
位的话,那么肯定会出错的,我们可以通过len(bin(12)[2:])-1
的方式得到3
,即低一位111
的情况,
然后就可以使用 C 3 3 C_3^3 C33的方式,求到1
然后剩下的,再从8
开始循环,到12
结束。
如此一来,可节约一定的时间。但还是没办法跑通最大的测试点。能多跑些分是些分吧。
【代码实现】
import functools
@functools.lru_cache()
def C(down, up):
fz, fm = 1, 1
for i in range(1, up + 1):
fm *= down
down -= 1
fz *= i
return fm // fz
n, k = map(int, input().split())
if k > len(bin(n)[2:]):
print(0)
exit()
l = len(bin(n)[2:]) - 1
c = C(l, k)
new_b = int('1' + '0' * l, 2)
for i in range(new_b, n + 1):
if bin(i).count('1') == k:
c += 1
print(c)
被自己蠢到了,考试的时候没想着直接写一个C方法,而是写了阶乘,然后用阶乘乘除得到Cxx,白白浪费时间。。。
时间限制: 2.0s 内存限制: 512.0MB 本题总分:25 分
【问题描述】
给定一个长度为 n n n 的括号序列,要求支持两种操作:
【输入格式】
输入的第一行包含两个整数 n , m n, m n,m,分别表示括号序列长度和操作次数。
第二行包含给定的括号序列,括号序列中只包含左括号和右括号。
接下来 m m m 行,每行描述一个操作。如果该行为 “ 1 1 1 L i L_i Li R i R_i Ri”,表示第一种操作, 区间为 [ L i , R i ] [L_i , R_i ] [Li,Ri] ;如果该行为 “ 2 2 2 L i L_i Li” 表示第二种操作,左端点为 L i L_i Li。
【输出格式】
对于每个第二种操作,输出一行,表示对应的 R i R_i Ri。如果不存在这样的 R i R_i Ri, 请输出 0 0 0。
【样例输入】
7 5
((())()
2 3
2 2
1 3 5
2 3
2 1
【样例输出】
4
7
0
0
【思路分析】
这个题跟冰山题一样,乍一看比较复杂,但其实也不难,一步步走就行。
这里也要注意避个坑:序列内的括号全部翻转。。这个我刚开始理解错了,不是顺序翻转,而是(
变)
,)
变(
。
判断是否有完整的括号序列,可以用这个方式实现,逐个删除完整括号,最后判断长度即可:
while '()' in s:
s = s.replace('()', '')
if len(s) == 0:
【代码实现】
n, m = map(int, input().split())
kh = list(input())
for i in range(m):
o = input().split()
if o[0] == '1':
l = int(o[1])
r = int(o[2])
for i in range(l - 1, r):
if kh[i] == '(':
kh[i] = ')'
else:
kh[i] = '('
else:
l = int(o[1])
r = n + 0
while r > l:
s = ''.join(kh[l - 1:r])
while '()' in s:
s = s.replace('()', '')
if len(s) == 0:
break
r -= 1
if r > l:
print(r)
else:
print(0)
完整题目及代码网盘自取:
https://pan.baidu.com/s/198t23JyVNftFSZzYyvYqKg
提取码:yoyo