2024蓝桥杯每日一题(背包2)

发布于:2024-03-29 ⋅ 阅读:(23) ⋅ 点赞:(0)

备战2024年蓝桥杯 -- 每日一题
Python大学A组

        试题一:包子凑数
        试题二:砝码称重
        试题三:倍数问题


试题一:包子称重

【题目描述】

        小明几乎每天早晨都会在一家包子铺吃早餐。他发现这家包子铺有 N 种蒸笼,其中第 i 种蒸笼恰好能放 Ai 个包子。每种蒸笼都有非常多笼,可以认为是无限笼。每当有顾客想买 X 个包子,卖包子的大叔就会迅速选出若干笼包子来,使得这若干笼中恰好一共有 X 个包子。比如一共有 3 种蒸笼,分别能放3、4 和 5 个包子。当顾客想买 11个包子时,大叔就会选 2 笼 3 个的再加 1 笼 5 个的(也可能选出 1 笼 3 个的再加 2笼 4 个的)。当然有时包子大叔无论如何也凑不出顾客想买的数量。比如一共有 33 种蒸笼,分别能放 4、5和 6 个包子。而顾客想买 7 个包子时,大叔就凑不出来了。小明想知道一共有多少种数目是包子大叔凑不出来的。

【输入格式】

        第一行包含一个整数 N。

        接下来 N 行,每行包含一个整数 Ai。

【输出格式】

        输出一个整数代表答案。

        如果凑不出的数目有无限多个,输出INF。

【数据范围】

        1≤N≤100
        1≤Ai≤100

【输入样例】

2
4
5

【输出样例】

6

【解题思路】

        容易看出是完全背包的变形,有几个物品,每个物品无限个,每个物品选任意个,能否凑到某个重量。题目说会出现有无限个数被凑不出来的, 说明这些数的gcd不是1。gcd为1呢?最大不能表示出来的数必定有个上界,因为两个数a,b(当gcd=1时),最大不能表示出来的数是:(a−1)(b−1)−1。当数字更多的时候,这个上界必然更小(可选的数字变多了),而99和98是100内最大的互质的数,所以这个上界选择10000。

【Python程序代码】

from math import *
n = int(input())
w = [0] + list(map(int,input().split()))
res = sum(w)
f = [[0]*(2*10**5+10) for _ in range(110)]
f[0][0]=1
for i in range(1,n+1):
    f[i][w[i]]=1
    for j in range(1,sum(w)+1):
        t = j-w[i]
        if t<0:t=-t
        f[i][j] += f[i-1][j] + f[i-1][j+w[i]] + f[i-1][t]
ans = 0
for i in range(1,sum(w)+1):
    if f[n][i]:
        ans+=1
print(ans)

试题二:砝码称重

【题目描述】

        你有一架天平和 N个砝码,这 N 个砝码重量依次是 W1,W2,⋅⋅⋅,WN。请你计算一共可以称出多少种不同的正整数重量?注意砝码可以放在天平两边。

【输入格式】

        输入的第一行包含一个整数 N。

        第二行包含 N 个整数:W1,W2,W3,⋅⋅⋅,WN。

【输出格式】

        输出一个整数代表答案。

【数据范围】

        对于 50% 的评测用例,1≤N≤15。
        对于所有评测用例,1≤N≤100,N 个砝码总重不超过 105。

【输入样例】

3
1 4 6

【输出样例】

10

【样例解释】

【解题思路】 

        可以看出是01背包的变形,在放与不放中的放中变成了放左边还是放右边,假设左边固定是物品,f[i][j]表示前i个砝码称体重为j的物体是否成功。所以当选择不放第i个物体时f[i-1][j],选择放左边时f[i-1][j+w[i]],选择放右边时f[i-1][ j-w[i] ]三种状态转移过来,初始化f[0][0]=1同时f[i][w[i]]=1。

【Python程序代码】

from math import *
n = int(input())
w = [0] + list(map(int,input().split()))
res = sum(w)
f = [[0]*(2*10**5+10) for _ in range(110)]
f[0][0]=1
for i in range(1,n+1):
    f[i][w[i]]=1
    for j in range(1,sum(w)+1):
        t = j-w[i]
        if t<0:t=-t
        f[i][j] += f[i-1][j] + f[i-1][j+w[i]] + f[i-1][t]
ans = 0
for i in range(1,sum(w)+1):
    if f[n][i]:
        ans+=1
print(ans)

试题三:倍数问题

【题目描述】

        众所周知,小葱同学擅长计算,尤其擅长计算一个数是否是另外一个数的倍数。但小葱只擅长两个数的情况,当有很多个数之后就会比较苦恼。现在小葱给了你 n 个数,希望你从这 n 个数中找到三个数,使得这三个数的和是 K 的倍数,且这个和最大。数据保证一定有解。

【输入格式】

        第一行包括 2 个正整数 n, K。

        第二行 n 个正整数,代表给定的 n 个数。

【输出格式】

        输出一行一个整数代表所求的和。

【数据范围】

        1≤n≤105,
        1≤K≤103,
        给定的 n 个数均不超过 108

【输入样例】

4 3
1 2 3 4

【输出样例】

9

【解题思路】

        这也是01背包的变形,不过还控制了选择的数量,因为是选三个数同时n的范围比k的范围大很多,所以可以优化一下n,也就是只取a[i]%k前三大的数,所以第一维枚举压缩到了k*3,第二维枚举三位数,从3开始枚举(主要原因是只用二维空间存储)只能从大的开始枚举,否则会出现重复。最后一维度枚举余数。具体看代码表述。

【Python程序代码】

n,K = map(int,input().split())
a = list(map(int,input().split()))
a.sort(reverse=True)
mp = [[]for _ in range(K+5)]
for i in range(len(a)):
    mp[a[i]%K].append(a[i])
f = [[-1e9]*(K+5) for _ in range(5)]
f[0][0]=0
for i in range(K):
    for u in range(0,min(3,len(mp[i]))):
        t = mp[i][u]
        for j in range(3,0,-1):
            for k in range(K):
                f[j][k] = max(f[j][k],f[j-1][ (k-i+K)%K ]+t)
print(f[3][0])
本文含有隐藏内容,请 开通VIP 后查看