【问题标题】:Sum of product of all subarray of length less than equal to k所有长度小于等于 k ​​的子数组的乘积之和
【发布时间】: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 &lt; n,我们有A[0]A[n - 1] 恰好出现在k 子数组中(大小小于或等于k)。找出cnt_i,每个索引i 出现的子数组A[i] 的数量取决于读者。从这里开始,答案将是sum(cnt_i * A[i]) % M,由于整数的大小限制,它可能必须拆分。

标签: c++ algorithm divide-and-conquer


【解决方案1】:

我们可以使用动态规划编写具有O(n) 复杂度的解决方案。

首先,我们将 dp[i] 定义为从数组 A 中的第 i 个位置开始的所有长度小于或等于 k ​​的子数组的乘积之和。 我们还将 b[i] 定义为从数组 A 中的第 i 个位置开始的长度为 k 的子数组的乘积(如果 i=nk)。

我们可以很容易地确定b[i] = ((b[i+1] * a[i]) / (a[i+k])) % M if(i+kb[i] = (b[i+1] * a[i]) % M if(i+k>n)。

我们还可以确定dp[i] = (a[i] * (dp[i+1]-b[i+1]) + a[i]) % M if(i+kdp[i]= (a[i] * dp[i+1] + a[i]) % M if (i+k>n)

问题的答案是dp[i]1&lt;=i&lt;=n 的总和

因此复杂度将是O(n)

【讨论】:

    猜你喜欢
    • 2016-01-01
    • 2017-03-16
    • 2016-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-25
    • 2019-12-18
    • 2018-03-03
    相关资源
    最近更新 更多