note = [2021 for i in range(0,10)]
i, flag = 1, 1
while flag:
now = i
while now:
if note[now % 10] == 0:
# 当第i张卡片需要的数字不够时,说明总共能拼到i-1
print(i - 1)
flag = 0
break
note[now % 10] -= 1
now //= 10
i += 1
答案:3181
# 直线可以用k(斜率)和b(与y轴的截距)唯一确定,因此可以看有多少个不同的(k,b)对
import pickle
s = set()
# 插入20 * 21个点
point = []
for i in range(0,20):
for j in range(0,21):
point.append([i,j])
for i in range(0,len(point) - 1):
for j in range(i + 1,len(point)):
x1,y1 = point[i]
x2,y2 = point[j]
# 横竖直线不考虑
if x1 == x2 or y1 == y2:
continue
k = (y2 - y1) / (x2 - x1)
# y = kx + b
# b = y - kx
# = y1 - k x1
# = (y1*x2 - y1*x1 - y2*x1 + y1*x1) / (x2 - x1)
# = (y1 * x2 - y2 * x1) / (x2 - x1)
b = (y1 * x2 - y2 * x1) / (x2 - x1)
if (k,b) not in s:
s.add((k,b))
print(len(s) + 41)
答案:40257
import math
n = 2021041820210418
x = []
# 长宽高都应该是n的因子,所以先找到n的因子
for i in range(1,int(math.sqrt(n)) + 1):
if n % i == 0:
x.append(i)
x.append(n // i)
ans = 0
# 枚举因子
for i in x:
for j in x:
for k in x:
if i * j * k == n:
ans += 1
print(ans)
答案:2430
import math
# 存储图
mp = [[math.inf] * 2025 for i in range(0,2025)]
# 存储点1到每个点的距离
dis = [math.inf for i in range(0,2025)]
dis[1] = 0
# 记录某个点是否被标记过
note = [False for i in range(0,2025)]
# 初始化mp
for i in range(1,2022):
for j in range(1,2022):
if math.fabs(i - j) <= 21:
mp[i][j] = mp[j][i] = i * j // math.gcd(i,j)
# dijkstra
while 1:
mn, k = math.inf, 0
for j in range(1,2022):
if (not note[j]) and dis[j] < mn:
mn, k = dis[j], j
if k == 0:
break
note[k] = True
for j in range(1,2022):
dis[j] = min(dis[j],dis[k] + mp[k][j])
print(dis[2021])
答案:10266837
思路写在注释里面了。
import math
# 用0 ~ 20来表示第1 ~ 21栋楼
# 一共可能出现0 -- 1<<21 - 1个数
# dp[i][j]表示数字i这个状态以第j栋楼结尾的路径的条数
dp = [[0] * 25 for i in range(0,1 << 21)]
# mp[i][j]用来表示i到j是否有路径
mp = [[False] * 22 for i in range(0,22)]
for i in range(1,22):
for j in range(1,22):
if math.gcd(i,j) == 1: # 互质说明有路径
mp[i - 1][j - 1] = True
# 000000000000000000001 这是初始时刻在第1(0)栋教学楼,这是二进制表示的数字是1
# 所以初始化dp[1][0] = 1,表示1这个数能以第0栋楼结尾的路径总数是1
dp[1][0] = 1
# 遍历1 ~ 111111111111111111111,看每个数字能通往哪些数字
for i in range(1,1 << 21):
# 遍历i的每一位,看是否已经走到过了第j位(第j栋楼)
for j in range(0,21):
# 没走到过
if not (i & 1 << j):
continue
# 走到过则遍历第j栋楼能到达的楼
for k in range(0,21):
# 第k栋楼已经被访问过或者jk之间没边
if (i & (1 << k)) or (not mp[j][k]):
continue
dp[i | (1 << k)][k] += dp[i][j]
print(sum(dp[(1 << 21) - 1]))
答案:881012367360