Given an array A of integers of size N, I want to compute
Since ai <= 200.000
and N<=200.000
, there might be 40.000.000.000 terms in total, but you know that ai + aj <= 400.000
. There can be at most 400.000 unique terms. That's already 5 orders of magnitude better.
However, most of these terms aren't primes; there only ~40.000 primes under 400.000. You may end up with a somewhat higher multiplicity of each individual term, but that's not a big deal. Calculating (prime^N) modulo 1000000007 is fast enough even for big X.
You can reasonably pre-calculate the factorization of all numbers <=400.000 and get the primes <=400.000 as a free side-effect.
This method achieves a speed-up because we delay multiplication, and instead count small prime factors found through a lookup. By the time we need to do the multiplications, we have a series of exponents and can use repeated squaring to efficiently reduce them.
It's counter-intuitive perhaps that we use prime factorization as a speed-up, when the "well-known fact" is that prime factorization is hard. But this is possible because each term is small, and we repeatedly need the same factorization.
[edit]
From the comments, it seems that figuring out the multiplicity of ai+aj
is hard, since you can only count the terms where i
i==j
. This is fixed by adding the multiplicity of all terms ai+ai prior to dividing by 2.
Ex: a={1 2 3}
, terms to consider are {1+1, 1+2, 1+3, 2+2, 2+3, 3+3}
[triangle]. The multiplicity of 4 is 2 (via 1+3 and 2+2). Instead, consider {1+1, 1+2, 1+3, 2+1, 2+2, 2+3, 3+1, 3+2, 3+3}
[square] + {1+1, 2+2, 3+3}
[diagonal]. The multiplicity of 4 is now 4 (1+3,2+2,3+1 and 2+2), divide by 2 to get the correct result.
And since the order of a[]
no longer matters for the square variant, you can use a counting sort on it. E.g. given {4,5,6,5}
, we get 4:1, 5:2, 6:1
. Thus the multiplicity of 10 is 4+6:1, 5+5:2, 6+4:1