距离蓝桥杯省赛还有41天时间,为了我们的梦想,鼓足干劲,冲冲冲!🐾🐾
卡片
这道题目的突破点就是要知道卡片0~9谁先用完。当发现这种卡片因为数量不够拼不成一个数字时,就能知道前面已经拼好几个数字了。
结合题目例子 “当小蓝有30张卡片,其中0到9各3张,则小蓝可以拼出1到10,但是拼11时卡片1已经只有一张了,不够拼出11。”,可以发现,最先用完的卡片是1。
知道了最先用完1后,我们就能每拼好一个数字,统计一次用掉1的个数,当凑不齐一个数字时,返回此时凑成的最后一个数字。
统计数字中1出现的个数,对于python而言,可以直接使用字符串的count函数来统计1出现的个数,只需要将数字由整型转化为字符串类型即可,显然这种方法是比较方便的。对于其他语言来说,需要分别得出 个十百千甚至万位上的数字,然后再来计算1出现的次数。
# 卡片
cnt = 2021
num = 0
while True: # 已有终止判断条件,这里可以设为True
n = str(num+1).count("1") # 统计下一个数字需要1的个数
if cnt >= n: # 如果能够凑齐就凑
cnt -= n # 减去凑齐这个数字需要用到1的个数
num += 1 # 凑齐这个数字后就要+1
else: # 否则就是凑不齐,凑不齐直接结束
break
print(num)
货物摆放
题目出的那么长,都能迷惑掉一大片考生了… 真正有用的就是 n = L x W x H 这个等式。 再结合一下例子可以知道因子的排列位置不同,就能产生不同的结果。
先说一下我做这题的思路。当时见到这道题我就想:“诶,这么大的数不会让我们在这里找吧?肯定有其他办法。”,想啊想,这么大的数前后一样,那肯定跟1有关,我一匹配一下,发现了。2021041820210418不就等于20210418 x 100000001 吗?然后我让100000001 分别除以1~9,发现都不是他的因子,脑袋一热就认定他是素数了,当时我就窃喜起来:“这道题能难得倒我?” 既然10000001是素数,那么它一定在长宽高的一个,只要找另外两个位置能够凑到20210418就OK了。因为20210418不大,我就用for找他的约数,最后匹配。等到对答案的时候却发现自己错了,怪不好意思的,还是太小看蓝桥杯了,呜呜呜,还得加把劲才行啊!!
分享完我的遭遇后现在就来锊一下题目的思路。解决这道题最先想到也是最容易想到的是暴力解法,通过三层遍历找到所有因子相乘之和能够等于2021041820210418 的三个数。但是种做法是不现实的,数那么大也许要跑到比赛结束才出结果,因此我们需要对这个解法进行一下优化。
我们可以先求出 2021041820210418 所有约数,然后让这些约数相乘看他们的的乘积是否与 2021041820210418 值相等,若相等,解决方案数+1。
可能有同学不懂为什么要先求出所有约数,然后再来求积呢?因为求积也是一项大工程,在茫茫数字中,约数只占极少数部分,其他数都是不相干的,这些不相干的数相乘之和也必然不是目标值,如果参与运算的话会产生大量无价值结果,因此,先求约数再来计算会比暴力解法效率高些。
得到约数后,我的方法是直接使用三层for循环列举它所有排列组合,然后匹配得出结果,但这么做的话挺暴力的。
重识暴力解法
在这里我说一下我对暴力解法的个人理解,希望大家不要对暴力解法有任何偏见。暴力解法固然不好,时间空间上都造成极大的浪费,缺点多多,但多少还是有个优点的,它的优点就是我们比较容易想到。在竞赛的填空题中我们不妨试一下,等个8~10秒又如何?只要不超过30秒都是可以接受的。也许你花15分钟设计的优化代码能够在15ms内得出结果,而花10分钟写的暴力解法需要在10000ms之后才能得出结果,那又如何?总体花费的时间或许暴力解法会少一些。因此我建议,在填空题中如果思考三五分钟还是没有得出理想的算法来解决题目的话,就试试稍微优化的暴力解法来解决。
下面我们看一下代码实现:
divisor = [] # 存放约数的列表
n = 2021041820210418 # 目标值
for i in range(1,int(n ** 0.5)+1): # 求约数在目标值的1/2次方范围内求取即可
if n % i == 0: # 如果可以整除
divisor.append(i) # 将其存入到约数列表中
div = int(n / i)
if div != i: # 如果目标除数的另一半不是他本身,也将其存入到约数列表中
divisor.append(div)
# print(divisor)
cnt = 0 # 计算 三个因子乘积等于目标值的方案总数
for i in divisor:
for j in divisor:
for k in divisor:
if i * j * k == n:
cnt += 1
print(cnt)
其实不会等太久,等个10秒就能出结果了。