A
# 法一:预设可排列数字范围,循环找1
cnt = 0
for i in range(1,10000): # 假设可以排列的数字从1到9999
for j in str(i):
if int(j) == 1: # 从1开始排,所以1最先用完
cnt += 1
if cnt == 2021:
print(i) # 3181
break
# 法二:while
'''
用str.count()方法统计字符串中某个字符出现的次数
'''
count = 0 # 计数器
i = 1 # 可以排列的数字
while True: # 循环次数未知,用while循环
count += str(i).count("1") # .count("1")方法:统计i中"1"出现的次数
if count >= 2021: # 如果"1"出现2021次,说明这次循环中卡片1刚好用完
print(i)
break
i += 1
B
"""
两点求线的斜率公式: k = (y1-y2)/(x1-x2)
截距公式: b = (x1*y2-x2*y1)/(x1-x2)
"""
points = [] # 存坐标
kbs = [] # 存斜率和截距
x = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]
y = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
# 生成坐标
for i in x:
for j in y:
point = (i,j)
points.append(point)
# 每两点计算斜率和截距
for i in range(len(points)):
for j in range(i+1, len(points)):
if points[i][0]-points[j][0] != 0: # 跳过k=0的线(20条)
tmp_k = (points[i][1]-points[j][1])/(points[i][0]-points[j][0])
tmp_b = (points[i][0]*points[j][1]-points[j][0]*points[i][1])/(points[i][0]-points[j][0]) # 注意截距公式
k_b = (tmp_k,tmp_b)
kbs.append(k_b)
kb_set = set(kbs) # 筛选重复值
print(len(kb_set)) # 40237,再加上k=0的20条为答案 40537
"""
学习一下一句话创建坐标
"""
M = [[x, y] for x in range(20) for y in range(21)] # 创建二维列表:代表xy坐标系
C
'''
不难,但要注意细节和思路,,
'''
num=2021041820210418
ys = {1}
# 找约数
for i in range(1,int(num**0.5)+1): # 缩小一下范围
if num % i == 0 :
tmp_y = num // i
ys.add(tmp_y)
ys.add(i)
# 三重for循环找满足题意的数字
cnt = 0
for a in ys:
for b in ys:
for c in ys:
if a*b*c == num: #条件
cnt += 1
print(cnt) # 2430
D
"""
最小公倍数+动态规划。小蓝大佬写得很清楚,这里直接照搬了,学习学习
动态规划的递推公式注意理解:
dp[i] #i:结点编号1~2021 #dp[i]:当前结点到结点1的最短路径长度
dp[j] #j:结点编号i+1~i+21 #dp[j]:当前结点到结点i的最短路径长度
此时dp[j]就在比较两个路径的长度,它只选择最短的那条路走:
第一条路:dp[j],代表之前存在dp列表里的最小路径(当前结点到结点1的最小路径)。
第二条路:dp[i]+lcm(i,j),代表假如现在的dp[i]加上新路lcm(i,j),这时候的路径长度。
比较dp[j]和dp[i]+lcm(i,j)哪条路更短,只走近路(min)的dp[j]就跟它走
无穷数:dp=[float('inf')]
"""
#最小公倍数模板(least common multiple)
def lcm(a,b):
s=a*b
while b:
a,b=b,a%b # 辗转相除,得最大公因数
return s//a # 乘积除最大公因数就是最小公倍数
#最短路径(dp)
n=2021 #结点数量
dp=[float('inf')]*(n+1) #创建n+1个无穷元素的列表
dp[1]=0 #结点1的长度初始化为0
for i in range(1,n+1): #结点a:遍历结点1~n
for j in range(i+1,i+22): #结点b:遍历结点i+1~i+21
if j>n: #j超出结点范围时
break #结束循环
dp[j]=min(dp[j],dp[i]+lcm(i,j))#递推公式
print(dp[n]) #输出结果:10266837
F
"""
时间模块的函数应用:
time.actime() 将时间元组转换为一个表示人类可读的时间字符串。
time.gmtime() 将该秒数解释为格林尼治标准时间(GMT)的时间元组。
这个时间元组包含了年、月、日、时、分、秒等信息。
n//1000 --> 毫秒和秒的转换,相差1000
print("{:02d}:{:02d}:{:02d}".format(h,m,s)) 控制输出两位数字
"""
# 法一
import time
n=int(input())
# 返回提取出其中的第 11 到第 19 个字符,即时间的小时、分钟和秒部分。
#这样就得到了形如 "HH:MM:SS" 的时间格式
print(time.asctime(time.gmtime(n//1000))[11:19])
# 法二:底层算法方法
n = 1618708103123
n //= 1000 # ms->s
n %= 24*60*60 #最近1天:4103s
s = n % 60 #23s
n //= 60 #s->min
h = n // 60 #1h
m = n % 60 #8min
# 注意输出格式
print("{:02d}:{:02d}:{:02d}".format(h,m,s))
G
思路:
第十二届蓝桥杯B组C/C++省赛—H题(杨辉三角)_思维题_杨辉三角最大路径题-CSDN博客
枚举顺序
首先对于左半边杨辉三角来说,每行最大的数一定出现在该行末尾,同时它也是该数最早出现的位置
因此我们不妨从第16斜行开始枚举,只要出现等于 n 的数直接返回位置即可
对于查找,我们可以对每个斜行采用二分的方法查找n
对于位置,我们可以在查找的时候确定,n所在行 r(不是斜行)和所在斜行 k ,然后通过等差公式 r*(r+1)/2 计算它之前数目的个数再加上 k+1
"""
小蓝的代码。思路是斜着找,但我没明白斜着的数组的规律
代码里有一些模板可以看看
"""
# 组合值模板
def C(a, b):
res = 1
fz = a #分子
for fm in range(1,b+1): #1~b
res = res * fz // fm#递推公式=分子//分母
fz -= 1
if res > n:
return res
return res
#二分查找
def check(k): #k:斜行
l, r = 2*k, n #赋初值left:2k right:n
while l < r:
mid = l + r >> 1 # >>1:相当于(l+r)//2
if C(mid, k) >= n:
r = mid
else:
l = mid + 1
if C(r, k) != n:
return False
print(r * (r + 1) // 2 + k + 1)#查找位置
return True
n = int(input())
if n == 1:
print(1)
else:
for k in range(16,0,-1):#从16斜行枚举
if check(k)==True:
break
# 不是答案的暴力,,构建杨辉三角形,转一维,顺序查找。
yh = []
for i in range(1000):
for j in range(i+1):
if i == 0:
yh.append([1])
continue
if j == 0:
tmp_list = []
tmp_list.append(1)
elif j == i:
tmp_list.append(1)
yh.append(tmp_list)
else:
tmp = yh[i-1][j-1]+yh[i-1][j]
tmp_list.append(tmp)
yh_one = []
for i in range(len(yh)):
for j in range(len(yh[i])):
yh_one.append(yh[i][j])
N = int(input())
for i in range(len(yh_one)):
if yh_one[i] == N:
print(i+1)
break