最小公倍数 SRM 661 Div1 250: MissingLCM
Problem Statement
The least common multiple (denoted "lcm") of a non-empty sequence of positive integers is the smallest positive integer that is divisible by each of them. For example, lcm(2)=2, lcm(4,6)=12, and lcm(1,2,3,4,5)=60.
Alice had a positive integer N. Then she chose some positive integer M that was strictly greater than N. Afterwards, she computed two values: the value A = lcm(N+1, N+2, ..., M) and the value B = lcm(1, 2, ..., M). She was surprised when she saw that A = B.the value A = lcm(N+1, N+2, ..., M) and the value B = lcm(1, 2, ..., M). She was surprised when she saw that A = B.the value A = lcm(N+1, N+2, ..., M) and the value B = lcm(1, 2, ..., M). She was surprised when she saw that A = B.the value A = lcm(N+1, N+2, ..., M) and the value B = lcm(1, 2, ..., M). She was surprised when she saw that A = B.the value A = lcm(N+1, N+2, ..., M) and the value B = lcm(1, 2, ..., M).
You are given the int N. Find and return the smallest M Alice could have chosen. (Such an M will always exist.)
Definition
- ClassMissingLCM
- MethodgetMin
- Parametersint
- Returnsint
- Method signatureint getMin(int N)
Limits
- Time limit (s)2.000
- Memory limit (MB)256
Constraints
- N will be between 1 and 1,000,000, inclusive.
Test cases
-
- N1
Returns2Alice needs to choose an M > 1 such that lcm(2,...,M) = lcm(1,...,M). We can see M=2 is the minimum value that works, since lcm(1,2) = lcm(2) = 2. -
- N2
Returns4 -
- N3
Returns6We have lcm(4,5,6) = lcm(1,2,3,4,5,6) = 60. -
- N4
Returns8 -
- N5
Returns10
-
- N42
Returns82Oh... that doesn't fit the pattern. -
-
- N999999
Returns1999966
-
-
In this problem the actual LCM values used can be notably large. It is best to avoid approaches that calculate them directly. Then how about we think of this problem in terms of the prime factorization of the numbers. For example, consider two numbers: 12 and 135. Their prime factorizations are:
22⋅3 and33⋅5 . The prime factorization of the LCM will be:22⋅33⋅5 . In other words, for each prime number , we take the maximum exponent of the prime number among the two numbers we are calculating the LCM for. How does this translate to the two LCMs used?A=LCM(N+1,N+2,...,M)
B=LCM(1,2,...,M)
A=B We need to translate this into distinct conditions, one for each relevant prime number:
a=max(ep(N+1),ep(N+2),...,ep(M))
b=max(ep(1),ep(2),...,ep(M))
a=b Where
ep(x) is the exponent of prime numberp in the prime factorization ofx , the maximum number of times you can repeatedly dividex byp . In words we just want the maximum exponent of primep among all the factorizations betweenN+1 andM and between1 andM to be equal. Try this:b=max(ep(1),ep(2),...,ep(N),ep(N+1),...,ep(M))
b=max(ep(1),ep(2),...,ep(N),max(ep(N+1),...,ep(M)))
b=max(ep(1),ep(2),...,ep(N),a) What happens here is we take advantage that the maximum operation is associative. This means
max(a,b,c)=max(a,max(b,c))=max(max(a,b),c) . The useful thing to conclude about this:b≥a . There's more:b=max(max(ep(1),ep(2),...,ep(N)),a)
c=max(ep(1),ep(2),...,ep(N))
b=max(c,a) We want
a=b=max(c,a) : This means we wantc≤a . Note thatc is constant, as it's determined by the numbers between 1 andN . So we just need to look for a value ofM such that the maximum exponent ofp amongN+1,N+2,...M is greater than or equal toc .There must be a number
x>N for whichep(x)≥c , this means that the exponent ofp in the prime factorization ofx . If we take the maximumep(i) for alli betweenN+1,...,M , the result would be at leastc , meaning that usingM=x would be correct.M=x+1 and anyM greater thanx would also be correct. If we find the minimumM that is valid forp , then we can assume that all greater numbers will also be valid forp . This minimumM will be the smallestx>N for whichep(x)≥c .Did you notice that in the examples it initially appears that the result is always
2N and then the result seems to be smaller than2N but not far apart?There is a good explanation for this.
c is the maximum exponent ofp for some number less than or equal toN , let's call that numberm .2m will also have that exponent forp (unlessp=2 , in which it will have an even larger exponent). Making2m a valid value forM . If we pickM=2N , we will guarantee that this happens for all relevant prime numbers. This is useful because it means we only need to search forx among numbers less than or equal to2N .For each prime
p , there will be a distinct minimum validM , we should pick the maximum out of all of them. This number will be valid for all primes we try. Note that whenp>N , anyM>N will be correct. Because whenp>N ,c is zero, none of the numbers smaller than or equal toN will be multiples ofp , so the maximum exponent will be 0. This means we only need to repeat this for all the prime numbers that are less than or equal toN .For each prime number we need to find
c and also find the minimumx such that:ep(x)>c andN<x≤2N . The final improvement we need is to notice that givenp , we only need to think in terms of numbers that are multiples ofp . Fori≤N , only values ofi that are multiples ofp will have an exponent ofp in their prime factor, so only they are relevant for the calculation ofc . Fori>N , only multiples ofp may have an exponent larger than or equal toc . In total we will try all the multiples ofp less than or equal to2N . This is repeated for eachp<N . The final number of steps needed is:2N2+2N3+2N5+...+2NP whereP is the maximum prime that doesn't exceedN . This number of steps is very good and the complexity would be similar to the Sieve of Eratosthenes'. A simple way to tell that complexity isO(NN−−√) : For allP>2N−−−√ ,2NP=1 . There are2N−2N−−−√ such values, this isO(N) . For the otherO(N−−√) values ofp , even if we assumedO(N) steps, the total complexity would still be:O(N+NN−−√) . We are ready to implement this solution:vector<int> get_primes(int N) { // Sieve of Erathostenes to find all the necessary prime numbers: vector<int> res; vector<bool> composite(N + 1, false); for (int p = 2; p <= N; p++) { if (! composite[p]) { for (int i = p+p; i <= N; i += p) { composite[i] = true; } res.push_back(p); } } return res; } int get_exponent(int x, int p) { int r = 0; while (x % p == 0) { r++; x /= p; } return r; } int getMin(int N) { int res = 2; // For each prime number <= N: for (int p: get_primes(N) ) { // first find the maximum exponent of p among numbers <= N // (in the explanation , this max_exp is c) int max_exp = 0; int i = p; while (i <= N) { max_exp = std::max(max_exp, get_exponent(i,p) ); i += p; } // seek the minimum i such that get_exponent(i,p) >= max_exp: while (get_exponent(i,p) < max_exp) { i += p; } // the maximum for all ps is the result: res = std::max(res, i); } return res; }