我想解决this CodeChef挑战:
假设给出了一个N(范围100,000)元素的数组A.我们要找到所有3对这样的元素的数量1< = Ai,Aj,Ak< = 30,000这样的
Aj-Ai = Ak- Aj and i < j < k
换句话说,Ai,Aj,Ak处于算术级数。例如对于Array:
9 4 2 3 6 10 3 3 10
所以AP是:
{2,6,10},{9,6,3},{9,6,3},{3,3,3},{2,6,10}
所以答案是5.
我尝试的是采用过去和过去命名的30,000个长阵列。最初右侧包含每个1-30,000元素的计数。
如果我们在第i个位置经过存储,则在i之前存储数组值的计数,并且在i之后存储数组的计数。我只是循环查找数组中所有可能的常见差异。这是代码:
right[arr[1]]--;
for(i=2;i<=n-1;i++)
{
past[arr[i-1]]++;
right[arr[i]]--;
k=30000 - arr[i];
if(arr[i] <= 15000)
k=arr[i];
for(d=1;d<=k;d++)
{
ans+= right[arr[i] + d]*past[arr[i]-d] + past[arr[i] + d]*right[arr[i]-d];
}
ans+=past[arr[i]]*right[arr[i]];
}
但这让我超时限时。请帮助更好的算法。
答案 0 :(得分:3)
如果您首先通过列表并且仅提取可能在其间具有3个术语AP的数字对(差异为0 mod 2),则可以大大缩短执行时间。然后在这些对之间进行迭代。
Pseudo C ++ - y code:
// Contains information about each beginning point
struct BeginNode {
int value;
size_t offset;
SortedList<EndNode> ends; //sorted by EndNode.value
};
// Contains information about each class of end point
struct EndNode {
int value;
List<size_t> offsets; // will be sorted without effort due to how we collect offsets
};
struct Result {
size_t begin;
size_t middle;
size_t end;
};
SortedList<BeginNode> nodeList;
foreach (auto i : baseList) {
BeginNode begin;
node.value = i;
node.offset = i's offset; //you'll need to use old school for (i=0;etc;i++) with this
// baseList is the list between begin and end-2 (inclusive)
foreach (auto j : restList) {
// restList is the list between iterator i+2 and end (inclusive)
// we do not need to consider i+1, because not enough space for AP
if ((i-j)%2 == 0) { //if it's possible to have a 3 term AP between these two nodes
size_t listOffset = binarySearch(begin.ends);
if (listOffset is valid) {
begin.ends[listOffset].offsets.push_back(offsets);
} else {
EndNode end;
end.value = j;
end.offsets.push_back(j's offset);
begin.ends.sorted_insert(end);
}
}
}
if (begin has shit in it) {
nodeList.sorted_insert(begin);
}
}
// Collection done, now iterate over collection
List<Result> res;
foreach (auto node : nodeList) {
foreach (auto endNode : node.ends) {
foreach (value : sublist from node.offset until endNode.offsets.last()) {
if (value == average(node.value, endNode.value)) {
// binary_search here to determine how many offsets in "endNode.offsets" "value's offset" is less than.
do this that many times:
res.push_back({node.value, value, endNode.value});
}
}
}
}
return res;
答案 1 :(得分:1)
这是一个简单的C版本解决方案,利用Ai + Ak必须进行测试:
#include <stdio.h>
static int arr[] = {9, 4, 2, 3, 6, 10, 3, 3, 10};
int main ()
{
int i, j, k;
int sz = sizeof(arr)/sizeof(arr[0]);
int count = 0;
for (i = 0; i < sz - 2; i++)
{
for (k = i + 2; k < sz; k++)
{
int ik = arr[i] + arr[k];
int ikdb2 = ik / 2;
if ((ikdb2 * 2) == ik) // if ik is even
{
for (j = i + 1; j < k; j++)
{
if (arr[j] == ikdb2)
{
count += 1;
printf("{%d, %d, %d}\n", arr[i], arr[j], arr[k]);
}
}
}
}
}
printf("Count is: %d\n", count);
}
和控制台运球:
tmp e$ cc -o triples triples.c
tmp e$ ./triples
{9, 6, 3}
{9, 6, 3}
{2, 6, 10}
{2, 6, 10}
{3, 3, 3}
Count is: 5
tmp e$
这个更复杂的版本保留了一个按值索引的Aj列表,从n-cubed到n-squared(有点)。
#include <stdio.h>
#include <stdint.h>
static uint32_t arr[] = {9, 4, 2, 3, 6, 10, 3, 3, 10};
#define MAX_VALUE 100000u
#define MAX_ASIZE 30000u
static uint16_t index[MAX_VALUE+1];
static uint16_t list[MAX_ASIZE+1];
static inline void remove_from_index (int subscript)
{
list[subscript] = 0u; // it is guaranteed to be the last element
uint32_t value = arr[subscript];
if (value <= MAX_VALUE && subscript == index[value])
{
index[value] = 0u; // list now empty
}
}
static inline void add_to_index (int subscript)
{
uint32_t value = arr[subscript];
if (value <= MAX_VALUE)
{
list[subscript] = index[value]; // cons
index[value] = subscript;
}
}
int main ()
{
int i, k;
int sz = sizeof(arr)/sizeof(arr[0]);
int count = 0;
for (i = 0; i < sz - 2; i++)
{
for (k = i; k < sz; k++) remove_from_index(k);
for (k = i + 2; k < sz; k++)
{
uint32_t ik = arr[i] + arr[k];
uint32_t ikdb2 = ik / 2;
add_to_index(k-1); // A(k-1) is now a legal middle value
if ((ikdb2 * 2) == ik) // if ik is even
{
uint16_t rover = index[ikdb2];
while (rover != 0u)
{
count += 1;
printf("{%d, %d, %d}\n", arr[i], arr[rover], arr[k]);
rover = list[rover];
}
}
}
}
printf("Count is: %d\n", count);
}
和运球:
tmp e$ cc -o triples triples.c
tmp e$ ./triples
{9, 6, 3}
{9, 6, 3}
{2, 6, 10}
{2, 6, 10}
{3, 3, 3}
Count is: 5
tmp e$