Coprimes [ACM ICPC Regionals 2014 - Asia Anshan]
Given a sequence a of n integers () where (), find the number of triplets (x, y, z) such that they are either pairwise coprime, or pairwise not coprime, feel free to check the problem statement for more explanation.
This problem was very interesting it combined various topics from combinatorics and number theory, first lets imagine each triplet as a triangle where the gcd of each pair of numbers is written on the side connecting them.
this seems like a lot of details, let’s just write 1 if the gcd is equal to 1, ≠1 otherwise, after doing this we would have four different types triangles.
let’s call them type A, B, C and D, now the answer to the problem is count(A) + count(D), but how do we calculate that? We already know that
So If only we could calculate count(B) + count(C) we could easily get the result by subtracting it from the previous equation.
Let’s fix some number as k can we calculate all triangles of type B and type C that has an left most vertex as k? call that f(k), we then have
Assume for now that we could calculate the cardinalities of those sets in a fast way, we’ll come back to this later, now if we sum f for all the numbers in the sequence what do we get ?
Not really what we expected, but why twice? we can have the same triangle while having a_i at X or at Y in case of type B, and at Y or at Z in case of type C.
However looking at what we got again
This makes the answer to the problem .
Now back to the part that we skipped which is how to calculate the cardinality of the sets we mentioned quickly.
We first have
so it’s sufficient to calculate only one of them, let’s rewrite k as
to calculate , we need to calculate
For sake of simplicity let
We calculate this using inclusion exclusion principle
Notice here that we replaced the intersection by multiplication because a number that is divisible by both p and q has to be divisible by p*q, we find that each number which have an odd number of primes is added into the result, and each number that has an even number of primes is subtracted from the result, and we never used numbers which have a repeated prime.
This weight function we used is called Möbius function μ(n), and it has other applications, it’s defined as
- μ(n) = 1 if n is square free and has odd number of prime divisors
- μ(n) = -1 if n is square free and has even number of prime divisors
- μ(n) = 0 if n is not square free
To implement this, we find that we have to iterate over the divisors of a number this is best done inversly, where each number goes to it’s multiples.
int freq[MAXN]; // freq[i]:count of times i occurs in the input
int multiplesOf[MAXN]; // multiplesOf[i]:count of numbers divisible by i
int share[MAXN]; // share[i]:count of numbers sharing common div with i
int mu[MAXN]; // Möbius function
…
// initializing multiplesOf
for(int i = 2;i<MAXN;i++)
for(int j = i;j<MAXN;j+=i)
multiplesOf[i]+=freq[j];
…
// initializing share
for(int i = 2;i<MAXN;i++)
for(int j = i;j<MAXN;j+=i)
share[j]+=multiplesOf[i] * mu[i];
After this precalculation we can calculate in O(1) time and thus solve the problem.