我需要一个有效的算法,该算法可以找到所有连续子序列之差的总和,但是我不知道该怎么做。
例如,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亿。
如何更快地做到?我需要算法。
答案 0 :(得分:0)
我的第一个想法是建立一棵树,以便记住子答案(即动态编程)并将答案组合在一起。但是,每个更高的分支并不一定严格来说就是其下的节点的总和。考虑例如:
摘要表示为
SUM( i * (n - i) )
和i = [1 .. n)
,其中n >=2
这当然是在O(N)时间中运行的,除了加+乘之外,不需要任何其他操作。
但是,令我困扰的是,这个求和公式可能会简化为一个简单的方程式。因此,我查找了properties of summation formulas并进行了简单的求解:
这意味着(n^3 - n) / 6
应该在O(1)时间执行。我对前6个进行了测试,并给出了正确的答案...