继续骂:煞笔洛谷、煞笔出题人
又是这种不清不楚、容易误导解题思路的题,题目中写了“为了在门口展出更多种花”,实际上在该题中,某些种类的花可以一盆都不摆。
小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共 m m m 盆。通过调查顾客的喜好,小明列出了顾客最喜欢的 n n n 种花,从 1 1 1 到 n n n 标号。为了在门口展出更多种花,规定第 i i i 种花不能超过 a i a_i ai 盆,摆花时同一种花放在一起,且不同种类的花需按标号的从小到大的顺序依次摆列。
正文
花盆问题和背包问题的区别:
背景:
- 背包问题中,每个物品的开销可能不同,每种物品数量不限制。
- 花盆问题中,每个物品的开销都为1,每种物品数量有限制。
求解目标不同:背包问题是找到最优组合,花盆问题是统计组合数量。
求解过程的差异:
- 背包问题不需要考虑物品数量的限制,所以可以从具有当前物品的前某一状态进行转移。
- 而花盆问题中,物品数量有限制,具有当前物品的前某一状态可能把物品数量使用完了,所以只能通过未使用当前物品的状态进行转移。
优化思路:
花盆容量小于等于当前物品数量情况下,物品数量的限制就无关紧要了,因为无论如何使用数量都不会超过限制,因此可以当作物品数量无限制来处理。这时,可以通过具有当前物品的前某一状态进行转移。
状态转移公式,
d
p
[
i
,
j
]
dp[i, j]
dp[i,j] 表示在有 i 个花盆,只有前 j 种花时的组合数量。
花盆容量小于等于当前物品数量情况下,取 1 ~ i 个或不取当前物品:
d
p
[
i
,
j
]
=
d
p
[
i
−
1
,
j
]
+
d
p
[
i
,
j
−
1
]
dp[i, j] = dp[i - 1, j] + dp[i, j - 1]
dp[i,j]=dp[i−1,j]+dp[i,j−1]
在花盆容量大于当前物品数量(数量为k)情况下:
d
p
[
i
,
j
]
=
s
u
m
(
d
p
[
i
−
k
,
j
−
1
]
.
.
.
d
p
[
i
,
j
−
1
]
)
dp[i, j] = sum(dp[i - k, j - 1]...dp[i, j - 1])
dp[i,j]=sum(dp[i−k,j−1]...dp[i,j−1])
代码:
def main():
mod = int(1e6 + 7)
n, m = map(int, input().split())
limit = list(map(int, input().split()))
dp = [1] * (1 + m)
res = [0] * (1 + m)
res[0] = 1
for j in range(n):
for i in range(1, m + 1):
dp[i] = sum(res[i - limit[j]:i + 1]) % mod if i > limit[j] else (dp[i - 1] + res[i]) % mod
dp, res = res, dp
print(res[-1])
main()