想说的话
大家好🌼🌼,我是 @愿此后再无WA,可以叫我小A,也可以叫我愿愿💡💡,一位阳光帅小伙,对算法领域比较感兴趣。如果我的文章对您有用,欢迎持续关注,我们一起进步!🎈🎈
很抱歉各位😪😪,现离蓝桥杯比赛不到一个月时间,我临时改变了计划,转为全心备战蓝桥,因为这个省一对我来说太重要了,也是我最后一次机会,我一定要拿到手📌📌,那么这样的话我在博客上花的时间就会少了很多,也将导致博客文章质量明显下降,在此我给大家说声抱歉💥💥
🌟🌟这些日子我真的很开心,博客上能遇到一群志同道合的兄弟姐妹真的很幸福,没有你们的支持与鼓励我早就坚持不下去了,因为有你们我才能走的更远????熬过这段时期我一定会回来的,爱你们????
分析
先理一下题目,题目的意思就是说,给你一串数字,找出所有不能通过这些数字拼出来数字的数量。比如,给出数字3,5。不能拼出来的数字有1,2,4,6,7…。可能有人以为无论给出哪些数字,不能拼出来的数字都是无限个,所以没法下手,其实呢,数学中已经得出了一个推论。 这个推论很重要,如果两个数互质,就有无法组成的最大整数,那么不能凑出的数字也就一一确定。还是以刚才3,5为例,根据上面的式子可以得出无法组成的最大整数是7(35-3-5=7)。8可以通过5+3得出,9可以通过33得出,10可以通过5+5得出。当连续凑出min(a,b)个数之后,之后的数字必定能凑出,11可以通过8+3得出,12可以通过9+3得出…等等。因此,3与5不能凑出数字的数量也就确定了。而不互质呢?如果两个数不互质,那么一定没有无法组成的最大整数,也就没有确定的无法组成数字的数量。为什么呢?因为两个数不互质,那么这两个数都是他们最大公约数的倍数,相当于那个公约数乘上若干数字得到这两个数的,而这样的话本体也就一个数,就是那个公约数。
思路
我们已经知道了唯有两数互质才有无法组成的最大整数,当出现N个数时,同样这么判断:遍历存放数字的列表,使用gcd两两比较得出最大公约数,如果是1(互质),就说明这个组里面一定存在无法组成的最大数。如果不是1,用这个公约数与下一个数字比较,如果是1,那么这个数字一定至少与前面的一个数字互质,如果不是1,继续用他们的最大公约数与下一个数比较,重复上述操作,直到找到两数互质或遍历完列表,如果遍历完列表gcd的结果仍不是1说明这些数之间没有一个数是互质的,可以返回“INF”,反之,如果发现至少有一个数互质,那么就能得到无法组成的最大数,然后在这个区间寻找无法凑出数字的数量。
找数的话就是用完全背包的思想去寻找,也就是一个数字可以取任意多次。如果不清楚这个知识点可以上bilibili大学自行学习。做这题的时候我才发现并理解原来一维01背包是从后往前遍历,一维完全背包是从前往后遍历的。
代码
我们可以根据 “当连续凑出min(a,b,c,d…)个数之后,之后的数字必定能凑出” 这一条件提前返回结果
def gcd(a,b):
if a > b:
a, b = b, a
while a > 0:
a, b = b % a, a
return b
def func():
N = int(input())
if N == 1:
return "INF"
nums = []
for i in range(N):
nums.append(int(input()))
nums.sort()
r = gcd(nums[0],nums[1])
for i in range(2,N+1):
if i < N:
r = gcd(r,nums[i])
if r == 1:
break
if r != 1:
return "INF"
dp = [False for i in range(int(1e4+1))]
ans = 0
cnt = 0
mi = nums[0]
for i in range(1, int(1e4+1)):
for j in nums:
if j > i:
continue
if j == i or dp[i - j]:
cnt += 1
dp[i] = True
break
if not dp[i]:
ans += 1
cnt = 0
if cnt == mi:
return ans
print(func())
|