0
点赞
收藏
分享

微信扫一扫

蓝桥 包子凑数【第八届】【省赛】【A组】python gcd 完全背包

小龟老师 2022-03-20 阅读 102

包子凑数

在这里插入图片描述
在这里插入图片描述

分析

先理一下题目,题目的意思就是说,给你一串数字,找出所有不能通过这些数字拼出来数字的数量。比如,给出数字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"
	
	 # 这里1e4足够了,因为100以内最大两个互质的数就是99跟100,他们乘积必定小于1e4
    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]:  # 如果没凑到总数量+1,以及连续数要清零
            ans += 1
            cnt = 0

		# 如果连续数已经等于数组最小值了,可以立马返回结果,因为后面的数必定能抽出来
        if cnt == mi:  
            return ans
print(func())

举报

相关推荐

0 条评论