第一题
问题描述
在今年蓝桥杯的决赛中,一共有 1010 道题目,每道题目的分数依次为 55 分,55 分,1010 分,1010 分,1515 分,1515 分,2020 分,2020 分,2525 分,2525 分。
假设某位参赛选手在解答每一道题时,要么能得到该题的全部分数,要么就得 00 分。那么请问,这位参赛选手在完成这 1010 道题之后,所能获得的总分值存在多少种不同的情况?
注意,总分值仅需关注选手 1010 道题的总得分,而无需关注具体是由哪些题获得了相应的分数。例如,选手第一道题获得 55 分其余题均为 00 分,与第二道题获得 55 分其余题均为 0 分,应视为同一种情况。
答案提交
这是一道结果填空题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
暴力法
python
# 题目分数列表
scores = [5, 5, 10, 10, 15, 15, 20, 20, 25, 25]
# 存储所有可能的总分(允许重复)
all_total = []
# 遍历所有可能的答题组合
# 第1题:0=不选,1=选
for q1 in [0, 1]:
# 第2题:0=不选,1=选
for q2 in [0, 1]:
# 第3题:0=不选,1=选
for q3 in [0, 1]:
# 第4题:0=不选,1=选
for q4 in [0, 1]:
# 第5题:0=不选,1=选
for q5 in [0, 1]:
# 第6题:0=不选,1=选
for q6 in [0, 1]:
# 第7题:0=不选,1=选
for q7 in [0, 1]:
# 第8题:0=不选,1=选
for q8 in [0, 1]:
# 第9题:0=不选,1=选
for q9 in [0, 1]:
# 第10题:0=不选,1=选
for q10 in [0, 1]:
# 计算当前组合的总分
total = (q1 * scores[0] +
q2 * scores[1] +
q3 * scores[2] +
q4 * scores[3] +
q5 * scores[4] +
q6 * scores[5] +
q7 * scores[6] +
q8 * scores[7] +
q9 * scores[8] +
q10 * scores[9])
# 将总分添加到列表中
all_total.append(total)
# 转换为集合去重,统计不同总分的数量
unique_total = set(all_total)
print(len(unique_total))
借助位运算
python
# 每道题的分数列表
scores = [5, 5, 10, 10, 15, 15, 20, 20, 25, 25]
# 初始化集合用于存储所有可能的总分(集合自动去重)
possible_scores = set()
# 使用位运算枚举所有可能的答题组合(2^10 = 1024种)
for combination in range(1 << 10): # 等价于2**10,使用位移运算更高效
total_score = 0
# 检查每道题是否答对(二进制位为1)
for question_idx in range(10):
if combination & (1 << question_idx): # 判断第question_idx位是否为1
total_score += scores[question_idx]
# 将当前组合的总分加入集合
possible_scores.add(total_score)
# 输出不同总分的数量
print(len(possible_scores))
-
外层循环
for combination in range(1 << 10)
1 << 10
表示2^10
(即 1024),生成从0
到1023
的整数。- 每个整数
combination
对应一个二进制数(如3
对应0000000011
,表示前两题答对)。
-
内层循环
for question_idx in range(10)
- 遍历每道题(
question_idx
从0
到9
),检查当前组合中该题是否答对。
- 遍历每道题(
-
关键判断
if combination & (1 << question_idx)
1 << question_idx
生成一个只有第question_idx
位为1
的二进制数(如question_idx=2
时为0000000100
)。combination & ...
通过按位与运算检查combination
的第question_idx
位是否为1
:- 若为
1
,说明该题答对,累加分数。 - 若为
0
,说明答错,不加分。
- 若为
动态规划法
python
scores=[5,5,10,10,15,15,20,20,25,25]
dp={0}
for score in scores:
sums=set()
for s in dp:
new_score= s+score
sums.add(new_score)
dp.update(sums)
print(dp)
print(len(dp))
-
暴力枚举法:通过 10 层嵌套循环遍历每道题的选或不选状态,计算所有组合的总分。这种方法直观但代码冗长,时间复杂度为 O (2^10)。
-
动态规划法:使用集合动态维护当前所有可能的总分值,每次处理一道题时扩展集合。这种方法代码简洁,时间复杂度为 O (N*M),其中 N 是题目数量,M 是可能的总分值数目。
第二题
问题描述
若一个正整数 n 满足
整除 2024!,即 2024!除以
的余数为 0,则称 n 为"儿童数"。
现在,请你计算在区间 [1,∞] 内一共有多少个"儿童数"。
答案提交
这是一道结果填空题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
我们需要计算所有满足 n^61 整除 2024! 的正整数 n 的个数。即:
-
素因子分解:
- 遍历 1 到 2024 的所有整数,对每个整数进行素因子分解。
- 使用
Counter
统计所有素数的总指数 vp(2024!)。
-
计算满足条件的 n 的个数:
-
对于每个素数 p,ap 的取值范围为:
-
因此,每个素数 p 有
种选择。
-
所有素数的选择数相乘即为满足条件的 n 的总数。
-
python
from collections import Counter
def prime_factor(x):
i = 2
while i * i <= x:
if x % i == 0:
d[i] += 1
x //= i
else:
i += 1
if x > 1:
d[x] += 1
d = Counter()
for i in range(1, 2025):
prime_factor(i)
res = 1
for v in d.values():
res *= (v // 61 + 1)
print(res)
解题思路详解:计算满足 n^61∣2024! 的正整数 n 的数量
- 问题转化:从整除条件到素因子指数约束
根据唯一分解定理,任何正整数 n 都可以表示为素数的幂次乘积:
因此,n^61 的素因子分解为:
题目要求 n61 整除 2024!,即:
其中 vp(2024!) 是素数 p 在 2024! 中的指数。由此可得:
- 计算素因子指数:Legendre 公式
对于素数 p,2024! 中 p 的指数 vp(2024!) 可通过 Legendre 公式 计算:
示例计算(以 p=2 为例):
- 组合计数:每个素数的指数选择
对于每个素数 p≤2024:
-
指数 ap 的取值范围为
。
-
共有
种选择。
由于不同素数的选择相互独立,根据乘法原理,满足条件的 n 的总数为:
- 关键说明
-
素数范围 :只需考虑 p≤2024,因为 p>2024 时
,此时 ap 必须为 0(贡献乘数 1)。
-
边界情况:若 vp(2024!)<61,则 ⌊61vp⌋=0,此时 ap 只能为 0(仍贡献乘数 1)。
python
# 第一步:判断一个数是否为素数(试除法)
def is_prime(num):
if num < 2:
return False # 0和1不是素数
for i in range(2, num):
if num % i == 0:
return False # 能被整除,不是素数
return True # 不能被整除,是素数
# 第二步:生成所有小于等于n的素数列表
def get_primes(n):
primes = []
for num in range(2, n + 1):
if is_prime(num):
primes.append(num)
return primes
# 第三步:计算n!中素数p的指数(Legendre公式)
def get_exponent(n, p):
exponent = 0
current = n
while current > 0:
current = current // p # 整除操作
exponent += current
return exponent
# 主程序
max_number = 2024 # 题目中的2024!
primes = get_primes(max_number) # 获取所有<=2024的素数
result = 1
for p in primes:
# 计算2024!中素数p的指数
exponent = get_exponent(max_number, p)
# 计算n中p的最大可能指数 a = exponent // 61
a = exponent // 61
# 每个素数的指数a有(a+1)种选择(0到a)
result *= (a + 1)
print(result) # 输出结果
第三题
问题描述
在篮球之都,有一支传奇的篮球队,名为"坤之队"。这支球队由 n 位才华横溢的球员组成,编号分别为 1,2,...,n。
今年,坤之队共参加了 m 场激烈的比赛。
在每场比赛前,坤之队的教练阿坤都会举行一个出征仪式。他会指定其中一名球员为队长,并将其球衣的号码设为 0。同时,为了保持队员之间的秩序和团结,教练还会对其他球员的球衣号码进行调整。具体来说,站在被指定球员右边的每个球员的球衣号码将比他左边球员的球衣号码大 1,而站在左边的每个球员的球衣号码将比他右边球员的球衣号码大 1。
举个例子,假设坤之队有 n=5 名球员,阿坤在一场比赛前指定编号为 3 的球员为队长,那么球员们球衣的号码就会变为 [2,1,0,1,2]。
经过 m 轮比赛的激烈角逐后,阿坤希望你能帮助他确定,每个球员所拥有过的最大球衣号码是多少。
输入格式
第一行包含两个正整数 n 和 m,表示球员数量和比赛场次数。
第二行包含 m 个整数 p1,p2,...,pm,表示每场比赛前被指定为队长的球员的编号。
输出格式
输出一行,包含 n 个整数,表示每个球员所拥有过的最大球衣编号。
python
n, m = map(int, input().split())
positions = list(map(int, input().split()))
result = [0] * n # 存储每个球员的最大球衣号码
for p in positions:
captain = p # 队长位置(1-based)
for i in range(n):
player = i + 1 # 球员位置(1-based,i是0-based索引)
distance = abs(captain - player) # 计算距离(即球衣号码)
if distance > result[i]:
result[i] = distance # 更新最大值
print(' '.join(map(str, result)))

每个球员的最大球衣号码取决于所有比赛中距离队长位置的最大距离。而这个最大距离可以通过分析所有队长位置的最小值和最大值来快速确定。
具体来说,对于任意球员位置 i
,其最大球衣号码为以下两者中的较大值:
- 该球员到所有比赛中最左侧队长位置的距离
- 该球员到所有比赛中最右侧队长位置的距离
这是因为最左侧和最右侧的队长位置能够产生最大的距离差,覆盖所有可能的情况。
python
n, m = map(int, input().split())
positions = list(map(int, input().split()))
# 初始化结果数组,每个元素初始为0
result = [0] * n
# 找出所有操作位置中的最小值和最大值(转换为0-based索引)
min_pos = min(positions) - 1 # 最小操作位置
max_pos = max(positions) - 1 # 最大操作位置
# 对于每个关键位置(最小和最大操作位置)
for critical_pos in [min_pos, max_pos]:
# 计算每个位置到关键位置的距离,并更新最大值
for i in range(n):
distance = abs(critical_pos - i)
if distance > result[i]:
result[i] = distance
print(*result)
暴力解法 | 优化解法 |
---|---|
逐次处理每场比赛 : 每次指定队长后,遍历所有球员,实时计算每个球员的当前距离 ,并更新最大值。 核心逻辑:每次操作独立计算,无状态复用。 | 利用全局极值 : 先找出所有队长位置的最小值 min_p 和最大值 max_p ,然后对每个球员,仅计算与这两个极值的距离 ,取最大值作为最终结果。 核心逻辑:最大值由边界位置决定,无需逐次计算。 |
举例 : 若有 100 场比赛指定队长位置,需重复 100 次遍历所有球员的操作。 | 举例 : 无论多少场比赛,只需计算两次距离(与min_p 和max_p ),复杂度与比赛次数无关。 |