好吧,看来我不能休息了:)
最简单的解决方案
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},
给定的可以通过用未知的 p 和 q 替换最后两个元素 n-2 和 n-1 来生成(较少顺序)
所以,元素的总和将是 (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 个)
最后检查找到的候选者是否真的出现在数组中两次。