一、子2023.
1. 考点:动态规划
2. 难度:⭐⭐⭐
3. 要点分析:
本题有两种做法,
(1)暴力求解。虽然时间复杂度挺高(跑了挺久),但在一定时间内是能够跑出正确答案的。
seq = ''
for i in range(1,2023+1):
seq += str(i)
s = ''
for t in seq:
if t in ['2','0','2','3']:
s += t
ans = 0
for i in range(len(s)):
if s[i]=='2':
for j in range(i+1,len(s)):
if s[j]=='0':
for p in range(j+1,len(s)):
if s[p]=='2':
for q in range(p+1,len(s)):
if s[q]=='3':
ans += 1
print(ans)
(2)动态规划。对于我本人来说比较难想一点,但确实开拓了一个新思路。
每多增加一个“2”,dp[0]+1,且对应的“202”的数目(dp[2])也会增加1*dp[1]个;
每多增加一个“0”,“20”的数目(dp[1])会增加1*dp[0]个;
每多增加一个“3”,“2023”的数目(dp[3])会增加多1*dp[2]个。
seq = ''
for i in range(1,2023+1):
seq += str(i)
s = ''
for t in seq:
if t in ['2','0','2','3']:
s += t
"""分别代表 2 20 202 2023"""
dp = [0]*4
for t in s:
if t=='2':
dp[0] += 1
dp[2] += dp[1]
if t=='0':
dp[1] += dp[0]
if t=='3':
dp[3] += dp[2]
print(dp[-1])
【考试时实在不行第一种,但练习时要学习第二种哈哈哈~】
二、双子数。
1. 考点:质因子分解
2. 难度:⭐⭐
3. 要点分析:
①在双层循环中,若不增加一些“筛选条件”,或是从start~end开始循环,时间复杂度都会比较大。
import math
def check(x):
for i in range(2,int(math.sqrt(x))+1):
if x%i==0:
return 0
return 1
"""将x开方 变为p*q的数 找到其中的p和q"""
start = int(math.sqrt(2333))
end = int(math.sqrt(23333333333333))
prime = [2,]
for i in range(3,end+1):
if check(i):
prime.append(i)
vis = [0]*(end+1)
for p in range(len(prime)):
for q in range(p+1,len(prime)):
x = prime[p]*prime[q]
if x>end:
break
if x<start:
continue
vis[x] = 1
print(sum(vis[start:]))
②尽管本次不需要对“素数的判断”进行优化,但还是记住“欧拉筛”比较好,说不定下次能够用上。其基本思想是,素数的倍数不是素数。
def ouler(r):
primes = []
check = [True for i in range(r+1)]
for i in range(2,r+1):
if check[i]:
primes.append(i)
for j in primes:
if i * j > r:
break
check[i*j] = False
if i % j == 0:
break
return primes
三、班级活动。
1. 考点:思维
2. 难度:⭐⭐⭐
3. 要点分析(详细解析可参考):考虑清楚“可配对”的情况:①id数等于1的学生自由配对;②id数超过2的学生全部改变;③id数等于1的学生和id数超过2的学生配对,仅需改变id数超过2的学生的id。由此,结合“最少变动”,得出改变方案。
【洛谷 P9421】[蓝桥杯 2023 国 B] 班级活动 题解(计数排序+贪心算法+数学)-CSDN博客
n = int(input())
numbers = list(map(int, input().split()))
ds = dict()
"""
有可能会出现同一数字出现多次的情况
每个数字只能出现两次 多于两次则需要更改
"""
# 统计次数
for t in numbers:
if t not in ds.keys():
ds[t] = 1
else:
ds[t] += 1
x = 0 #待分配id的学生
y = 0 #id重复的学生
for t in list(ds.keys()):
if ds[t] == 1:
x += 1
elif ds[t] > 2:
y += ds[t]-2
# x<=y 只需要改变id重复的学生即可
if x<=y:
print(y)
# x>y 1.改变id重复的学生以适配;2.剩余待分配学生两两配对
else:
print((x-y)//2+y)
四、合并数列。
1. 考点:模拟、双指针
2. 难度:⭐⭐⭐
3. 要点分析:
①利用“双指针”时,不要改变指针指向的数组的内容;而是选择另一个衡量标准——“当前的数组和是否相等”。
②当使用“while循环”时,需格外注意其循环条件:有可能p==n-1,但此时q!=(m-1)且sumA!=sumB。但两个数组的数组和必然是相等的,因此只需要再合并数组余下的数即可。
n, m = map(int, input().split())
a = list(map(int, input().split()))
b = list(map(int, input().split()))
p=0;q=0
sumA=0;sumB=0
ans = 0
while p<n and q<m:
if sumA==sumB:
sumA += a[p]
sumB += b[q]
p+=1;q+=1
elif sumA<sumB:
sumA += a[p]
p += 1
ans += 1
elif sumA>sumB:
sumB += b[q]
q += 1
ans += 1
print(ans+n+m-p-q)
五、数三角。
1. 考点:枚举
2. 难度:⭐⭐⭐
3. 要点分析:该题解在pyp3能过,python只能达到65%。
①对于平面上的每一个点P,计算其与其它所有点的距离。
②以P点位顶点,计算其与其它两点能否构成三角形。
注:本题的思路不难,难在“优化”上;如何减少代码的时间复杂度。
import math
n = int(input())
dots = []
for i in range(n):
x, y = map(int, input().split())
dots.append([x,y])
ans = 0
# 以p点为圆心,记录不同点与点p的距离
for p in range(n):
dockers = {}
for q in range(n):
if p==q:
continue
x1,y1 = dots[p]
x2,y2 = dots[q]
dis = math.sqrt((x1-x2)**2+(y1-y2)**2)
if dis not in dockers:
dockers[dis] = [q]
else:
dockers[dis].append(q)
for dis in dockers:
if len(dockers[dis])>=2:
# 判断是否能组成三角形
for i in range(len(dockers[dis])):
for j in range(i+1,len(dockers[dis])):
x1,y1 = dots[dockers[dis][i]]
x2,y2 = dots[dockers[dis][j]]
tmp = math.sqrt((x1-x2)**2+(y1-y2)**2)
if tmp < 2*dis:
ans += 1
print(ans)