如何找到所有连续子序列的差异?

时间:2018-10-27 09:26:26

标签: c++ dynamic-programming

我需要一个有效的算法,该算法可以找到所有连续子序列之差的总和,但是我不知道该怎么做。

例如,12345的所有连续子序列:

12    (Dif = 1)
23    (Dif = 1)
34    (Dif = 1)
45    (Dif = 1)
123   (Dif = 2)
234   (Dif = 2)
345   (Dif = 2)
1234  (Dif = 3)
2345  (Dif = 3)
12345 (Dif = 4)

Sum of the difference = 20

序列元素的数量> = 2 <= 300000。

每个元素> = 1 <= 10 ^ 7。

时间限制:1秒。

我写了代码,但是太慢了:

#include <bits/stdc++.h>

using namespace std;

int main() {
    cin.tie(0);
    iostream::sync_with_stdio(false);

    int count;
    cin >> count;

    int elem;

    vector<int> vec;
    int sum = 0;

    for (int i = 0; i < count; i++) {
        cin >> elem;

        if (vec.size() > 0) {
            sum += abs(vec.back() - elem);
        }

        vec.push_back(elem);
        if (vec.size() > 2) {
            sum += abs(*max_element(vec.begin(), vec.end()) -             *min_element(vec.begin(), vec.end()));
        }

        for (int z = 3; z < count; z++) {
            if (vec.size() > z) {
                sum += abs(*max_element(vec.begin() + i - z + 1, vec.end()) - *min_element(vec.begin() + i - z + 1, vec.end()));
            }
        }
    }

    cout << sum;

    return 0;
}

我发现可以通过三角数公式(其中n-序列长度)找到子序列的数量:

count = 1/2 * n * (n - 1);

对于n = 300000,子序列数为450亿。

如何更快地做到?我需要算法。

1 个答案:

答案 0 :(得分:0)

我的第一个想法是建立一棵树,以便记住子答案(即动态编程)并将答案组合在一起。但是,每个更高的分支并不一定严格来说就是其下的节点的总和。考虑例如: enter image description here

但是,我注意到节点是可预测的。即: enter image description here

当扩展到6个连续节点时: enter image description here

摘要表示为

SUM( i * (n - i) )i = [1 .. n),其中n >=2

这当然是在O(N)时间中运行的,除了加+乘之外,不需要任何其他操作。


但是,令我困扰的是,这个求和公式可能会简化为一个简单的方程式。因此,我查找了properties of summation formulas并进行了简单的求解:

enter image description here

这意味着(n^3 - n) / 6应该在O(1)时间执行。我对前6个进行了测试,并给出了正确的答案...