【发布时间】:2021-12-29 18:04:22
【问题描述】:
我正在尝试解决以下问题。
给定大小为n 的整数数组称为A。从A 中找到长度小于k 并以M 为模的所有可能子数组的乘积之和。例如
A = [9 1 90]
k = 2
M = 10
那么要求的总和将是:
sum = (9 + 1 + 90 + (9 * 1) + (1 * 90)) % 10 = 9
我首先尝试了一个简单的动态规划,只要在A 上进行迭代,它花费了 O(nk) 并且它得到了时间限制错误。 cpp中提到的代码如下:
int main() {
int n, k, M;
cin >> n >> k >> M;
long long int D[n][n];
int sum_ = 0;
for (size_t i = 0; i < n; i++)
{
int temp;
cin >> temp;
temp %= M;
D[i][i] = temp;
sum_ = ((sum_ + temp) % M);
}
for (size_t t = 1; t < k; t++)
{
size_t i = 0, j = t;
while (j < n) {
int mid = (i + j) / 2;
int temp = (D[i][mid] * D[mid+1][j]) % M;
D[i][j] = temp;
sum_ = ((sum_ + (temp % M)) % M);
i ++;
j ++;
}
}
cout << sum_ << endl;
return 0;
}
所以现在我正在考虑一种分而治之的方法来在 O(nlogn) 中解决它,但我想不出任何好的解决方案。
有什么方法可以在 O(nk)(或 O(n.n))的更好时间复杂度内解决这个问题。
【问题讨论】:
-
从
A创建一个前缀产品数组。然后将大小为k的窗口移动到上一步的前缀乘积数组上,并对每个窗口的结果求和。这一切都是在O(n)时空完成的。 -
我建议使用乘法的分配属性。假设
k < n,我们有A[0]和A[n - 1]恰好出现在k子数组中(大小小于或等于k)。找出cnt_i,每个索引i出现的子数组A[i]的数量取决于读者。从这里开始,答案将是sum(cnt_i * A[i]) % M,由于整数的大小限制,它可能必须拆分。
标签: c++ algorithm divide-and-conquer