参考文章:AcWing 蓝桥杯包子凑数. ---欧几里得的应用、【蓝桥杯国赛真题笔记】Python、蓝桥杯 k倍区间(蒟蒻版)
1.包子凑数
#(1)判断结果是否为 inf
# 两个数互质,它们不能表示的最大数字为 p*q-p-q,即这两个数组合的不能表示的数有限
# 所以两数的最大公约数为 1 时,不能表示的数为有限个
# 类推,gcd(a,b,...)=1时,不能表示的数字为有限个
#(2)结果有限时确定凑不出的数目
# 由于凑不出的数取决于最大的互质包子数目,这里最大包子数为100,与其互质的最大包子数为99,
# 即无论有任何其它互质包子数,不能凑出的数也不能超过9900,所以就从1——9900这个区间判断是否可以凑出
def gcd(a,b):
return a if b==0 else gcd(b,a%b)
N=int(input())
nums=[int(input()) for _ in range(N)]
gcd_big_small=max(nums)*min(nums)-max(nums)-min(nums)
dp=[False]*10000
#判断结果是否为 inf
# 只要有两个数互质,d=1,结果就不为 inf
d=nums[0]
for i in range(1,N):
d=gcd(d,nums[i])
if d!=1:
print('INF')
else:
#dp[i]表示是否能凑出i个包子
dp[0]=True
for k in range(gcd_big_small):
for j in range(N):
if dp[k]:
dp[k+nums[j]]=True
ans=0
#显然最大的不能凑出的数为 gcd_big_small,下标要加 1
for i in range(gcd_big_small+1):
if not dp[i]:
# print(i,end=' ')
ans+=1
print(ans)
2.K倍区间
等价于求前缀和数组中模k得到的值相同的区间的对数加上模K为0的个数
N,K=map(int,input().split())
nums=[int(input()) for _ in range(N)]
#前缀和,起始前缀为nums[0],直接赋上
presum=[nums[0]%K]+[0]*(N-1)
#cnt统计前缀后模K结果为i的个数
#第一个数的前缀和为本身,其取模后的结果的个数加1
cnt=[0]*K
cnt[presum[0]]=1
ans=0
for i in range(1,N):
#求前缀和并取模
presum[i]=presum[i-1]+nums[i]
presum[i]%=K
#ans在cnt+=1前,表示只有当前面计算过的取模结果出现与之相同的才加
#若反过来则会出现,比如只有一个取模结果为5的,先cnt+=1,再ans+=cnt,显然ans加多了1次
ans+=cnt[presum[i]]
cnt[presum[i]]+=1
# print(presum)
# print(cnt)
print(ans+cnt[0])
3.青蛙跳杯子
import collections
astring=list(input())
bstring=list(input())
length=len(astring)
#三部曲:方向数组、前驱列表、队列
# 这里将 * 看作‘会跳的青蛙’使之变成单源BFS,其实实际上 一次也只有一个青蛙能跳,但多个青蛙难以确定,得换个思路
Move=[1,2,3,-1,-2,-3]
pre=[astring]
queue=collections.deque([(astring,0)])
while queue:
if queue[0][0]==bstring:
print(queue[0][1])
break
else:
index=queue[0][0].index('*')
for i in range(6):
# 列表复制用 .copy()
tmp=queue[0][0].copy()
new_index=index+Move[i]
if 0<=new_index<length:
tmp[index],tmp[new_index]=tmp[new_index],tmp[index]
# print(tmp)
if tmp not in pre:
pre.append(tmp)
queue.append((tmp,queue[0][1]+1))
queue.popleft()
# list=['s','A']
# print(list.index('A'))