「力扣挑战赛」 的入场仪式马上就要开始了,由于安保工作的需要,设置了可容纳人数总和为 M
的 N
个安检室,capacities[i]
记录第 i
个安检室可容纳人数。安检室拥有两种类型:
- 先进先出:在安检室中的所有观众中,最早进入安检室的观众最先离开
- 后进先出:在安检室中的所有观众中,最晚进入安检室的观众最先离开
恰好 M+1
位入场的观众(编号从 0 开始)需要排队依次入场安检, 入场安检的规则如下:
- 观众需要先进入编号
0
的安检室 - 当观众将进入编号
i
的安检室时(0 <= i < N
),- 若安检室未到达可容纳人数上限,该观众可直接进入;
- 若安检室已到达可容纳人数上限,在该观众进入安检室之前需根据当前安检室类型选择一位观众离开后才能进入;
- 当观众离开编号
i
的安检室时 (0 <= i < N-1
),将进入编号i+1
的安检室接受安检。
若可以任意设定每个安检室的类型,请问有多少种设定安检室类型的方案可以使得编号 k
的观众第一个通过最后一个安检室入场。
注意:
- 观众不可主动离开安检室,只有当安检室容纳人数达到上限,且又有新观众需要进入时,才可根据安检室的类型选择一位观众离开;
- 由于方案数可能过大,请将答案对
1000000007
取模后返回。
示例 1:
输入:
capacities = [2,2,3], k = 2
输出:
2
解释:
存在两种设定的2
种方案:
- 方案 1:将编号为
0
、1
的实验室设置为 后进先出 的类型,编号为2
的实验室设置为 先进先出 的类型;- 方案 2:将编号为
0
、1
的实验室设置为 先进先出 的类型,编号为2
的实验室设置为 后进先出 的类型。以下是方案 1 的示意图:
示例 2:
输入:
capacities = [3,3], k = 3
输出:
0
示例 3:
输入:
capacities = [4,3,2,2], k = 6
输出:
2
提示:
1 <= capacities.length <= 200
1 <= capacities[i] <= 200
0 <= k <= sum(capacities)
思路:一道容易被题目规则和背景唬住的题目,透过现象看本质会发现其实是一道水的不能再水的题目。题目中n个容器无非就只有“队列”和“栈”两种,我们简单的思考下:对于队列来说是不会改变当前序列的顺序的。而对于栈来说,我们会发现这个容器会让序列中的一个元素往前提了size-1位,其中size为容器的大小。因此这道题本质上就是问我们能从这n个容器中怎么挑选容器,使得这几个容器使用“栈”规则保证第k个元素提到第一个位置上。我们可以通过01背包来解决这个问题。代码是非常简洁的:
class Solution {
private static final int mod = 1000000007;
public int securityCheck(int[] capacities, int k) {
long ans = 0;
int n = capacities.length;
long[] dp = new long[40005];
dp[0] = 1;
for (int i = 0; i < n; i++) {
for (int j = k; j >= capacities[i] - 1; j--)
dp[j] = (dp[j] + dp[j - capacities[i] + 1]) % mod;
}
return (int) dp[k];
}
}