Maximum Product of Subsequences With an Alternating Sum Equal to K
Maximum Product of Subsequences With an Alternating Sum Equal to K
You are given an integer array nums
and two integers, k
and limit
. Your task is to find a non-empty subsequence of nums
that:
- Has an alternating sum equal to
k
. - Maximizes the product of all its numbers without the product exceeding
limit
.
Return the product of the numbers in such a subsequence. If no subsequence satisfies the requirements, return -1.
The alternating sum of a 0-indexed array is defined as the sum of the elements at even indices minus the sum of the elements at odd indices.
Example 1:
Input: nums = [1,2,3], k = 2, limit = 10
Output: 6
Explanation:
The subsequences with an alternating sum of 2 are:
[1, 2, 3]
- Alternating Sum:
1 - 2 + 3 = 2
- Product:
1 * 2 * 3 = 6
- Alternating Sum:
[2]
- Alternating Sum: 2
- Product: 2
The maximum product within the limit is 6.
Example 2:
Input: nums = [0,2,3], k = -5, limit = 12
Output: -1
Explanation:
A subsequence with an alternating sum of exactly -5 does not exist.
Example 3:
Input: nums = [2,2,3,3], k = 0, limit = 9
Output: 9
Explanation:
The subsequences with an alternating sum of 0 are:
[2, 2]
- Alternating Sum:
2 - 2 = 0
- Product:
2 * 2 = 4
- Alternating Sum:
[3, 3]
- Alternating Sum:
3 - 3 = 0
- Product:
3 * 3 = 9
- Alternating Sum:
[2, 2, 3, 3]
- Alternating Sum:
2 - 2 + 3 - 3 = 0
- Product:
2 * 2 * 3 * 3 = 36
- Alternating Sum:
The subsequence [2, 2, 3, 3]
has the greatest product with an alternating sum equal to k
, but 36 > 9
. The next greatest product is 9, which is within the limit.
Constraints:
1 <= nums.length <= 150
0 <= nums[i] <= 12
-105 <= k <= 105
1 <= limit <= 5000
解题思路
dp 还是很容易想到的,就是不好处理乘积不超过 $\text{limit}$ 这个条件。显然我们不能直接像 01 背包那样 dp 求个满足交错和等于 $k$ 的子序列的乘积最大值,因为有可能会超过 $\text{limit}$,为此我们需要把 $\text{limit}$ 当作 dp 状态的一维。
先不管会不会超时或爆空间,定义布尔状态 $f(i,j,k,u \in \{1/-1\},v \in \{0/1\})$ 表示是否存在由前 $i$ 个元素构成交错和为 $j$,且乘积为 $k$,下一个元素在交错和中的系数是 $1/-1$,序列是否为空 $(0/1)$ 的子序列。为了方便,这里考虑当前状态可以转移到哪些状态。根据选或不选第 $i+1$ 个元素进行状态转移:
\begin{cases}
f(i,j,k,u,v) \to f(i+1,j + u \cdot a_{i+1},k \cdot a_{i+1}, -u, 1) \\
f(i,j,k,u,v) \to f(i+1,j,k,u,v)
\end{cases}
考虑 $n$,$k$,$\text{limit}$ 的最大值,状态的数量级大约为 $10^{11}$。不过容易发现,由于 $n$ 最大只有 $150$,交错和不可能达到 $10^5$ 的级别。事实上考虑最糟糕的情况,即 $n = 150$,偶数位都是 $12$,奇数位都是 $0$,此时有最大交错和 $\frac{150}{2} \cdot 12 = 900$。所以实际上状态的数量级应该约为 $10^9$,不过还是很大就是了。
实际上我们应该更关注乘法有多少种可能的结果,$150$ 个 $0 \sim 12$ 的数相乘,能得到多少种不同的结果。通过打表可以发现,实际上只有 $395$ 种不同结果,远远小于 $5000$!是怎么注意到种类很少的呢?这是因为相乘的结果只能通过 $12$ 以内的质数($2,3,5,7,11$)组合得到,因此直觉上会猜相乘结果的种类很少。用到这个技巧的还有 Count Beautiful Numbers。
打表代码
#include <bits/stdc++.h>
using namespace std;
int main() {
unordered_set<int> st({1});
for (int i = 1; i <= 150; i++) {
unordered_set<int> t;
for (int j = 0; j <= 12; j++) {
for (auto &x : st) {
int p = x * j;
if (p <= 5000) t.insert(p);
}
}
cout << i << ": " << t.size() << '\n';
st.insert(t.begin(), t.end());
}
return 0;
}
另外注意到,对于一个相乘结果不超过 $5000$ 的子序列,其中大于 $1$ 的值的数量不超过 $\left\lfloor \log{5000} \right\rfloor = 12$ 个。对应到子序列的交错和中,考虑最粗略的情况,即有 $12$ 个 $12$ 在偶数位,其余都是 $1$,此时的交错和也只有 $(12-1) \cdot 12 + (1-1) (75-12) = 132$,因此交错和实际上也是很少的。
所以实际上状态的数量级最大只有 $10^6$。
如果用循环递推进行 dp 则需要对可能的交错和以及乘积结果进行离散化,很麻烦。所以用记忆化搜索,开个 std::set<std::array<int, 5>>
来记录搜索过的状态避免重复搜索就行。另外需要注意处理乘积结果超过 $\text{limit}$ 的情况,剩下的细节见代码。
AC 代码如下:
class Solution {
public:
int maxProduct(vector<int>& nums, int k, int limit) {
int n = nums.size();
if (abs(k) > (n + 1) / 2 * 12) return -1;
set<array<int, 5>> st;
int ret = -1;
auto dfs = [&](auto &&dfs, int u, int s, int p, int c, int f) {
if (u == n) {
if (s == k && p <= limit && f) ret = max(ret, p);
return;
}
if (st.count({u, s, p, c, f})) return;
st.insert({u, s, p, c, f});
dfs(dfs, u + 1, s, p, c, f);
dfs(dfs, u + 1, s + c * nums[u], min(limit + 1, p * nums[u]), -c, 1);
};
dfs(dfs, 0, 0, 1, 1, 0);
return ret;
}
};
参考资料
暴力出奇迹:如何分析状态个数(Python/Java/C++/Go):https://leetcode.cn/problems/minimum-operations-to-make-elements-within-k-subarrays-equal/solution/hua-dong-chuang-kou-zhong-wei-shu-hua-fe-e9cn/
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/18811880