ОК, кажется, я просто не могу дать ему отдохнуть :)
Самое простое решение
int A[N] = {...};
int signed_1(n) { return n%2<1 ? +n : -n; } // 0,-1,+2,-3,+4,-5,+6,-7,...
int signed_2(n) { return n%4<2 ? +n : -n; } // 0,+1,-2,-3,+4,+5,-6,-7,...
long S1 = 0; // or int64, or long long, or some user-defined class
long S2 = 0; // so that it has enough bits to contain sum without overflow
for (int i=0; i<N-2; ++i)
{
S1 += signed_1(A[i]) - signed_1(i);
S2 += signed_2(A[i]) - signed_2(i);
}
for (int i=N-2; i<N; ++i)
{
S1 += signed_1(A[i]);
S2 += signed_2(A[i]);
}
S1 = abs(S1);
S2 = abs(S2);
assert(S1 != S2); // this algorithm fails in this case
p = (S1+S2)/2;
q = abs(S1-S2)/2;
Одна сумма (S1 или S2) содержит p и q с одинаковым знаком, другая сумма - с противоположными знаками, все остальные члены исключаются.
S1 и S2 должны иметь достаточно битов для размещения сумм, алгоритм не означает переполнение из-за abs ().
если abs (S1) == abs (S2), то алгоритм завершится неудачно, хотя это значение все равно будет разницей между p и q (то есть abs (p - q) == abs (S1)).
Предыдущее решение
Я сомневаюсь, что кто-нибудь когда-нибудь столкнется с такой проблемой в поле;)
и я думаю, я знаю ожидание учителя:
Давайте возьмем массив {0,1,2, ..., n-2, n-1},
Данный можно получить, заменив два последних элемента n-2 и n-1 неизвестными p и q (меньший порядок)
итак, сумма элементов будет (n-1) n / 2 + p + q - (n-2) - (n-1)
сумма квадратов (n-1) n (2n-1) / 6 + p ^ 2 + q ^ 2 - (n-2) ^ 2 - (n-1) ^ 2
Остается простая математика:
(1) p+q = S1
(2) p^2+q^2 = S2
Конечно, вы не решите это, поскольку математические классы учат решать квадратные уравнения.
Сначала вычислим все по модулю 2 ^ 32, то есть допустим переполнение.
Затем проверьте пары {p, q}: {0, S1}, {1, S1-1} ... по выражению (2), чтобы найти кандидатов (их может быть больше 2 из-за модуляции и возведения в квадрат)
И, наконец, проверьте найденных кандидатов, если они действительно присутствуют в массиве дважды.