LCM of a range - problem 255

Back to General discussions forum

CSFPython     2022-01-06 20:11:23

I logged in to the site to propose a new problem, only to find that 3 more problems have appeared since I last logged in! My suggestion is not as imaginative as those but hopefully will provide a good challenge. It is only of medium difficulty so should attract a good number of solutions.

The motivation for this problem is to take a fairly routine calculation and to change the parameters in such a way that we introduce a kind of puzzle element into the solution. More specifically, what we have here is a problem where the "obvious" solution is soon found to be impractical. We then have to think about the problem, answering such questions as "What is going on here?" and "What is actually needed in order to find the solution to the problem?". A good analysis of the problem should soon lead to a method for solving it. There is another twist here. The most likely method that presents itself at this point is not the best. Further thought based on this solution should reveal how it can be made much better. I made a decision that the routine used for creating the problem (4 sets of data), together with the solutions, should not take more than 1 second. Because of this, the less efficient method should still execute in around 1 minute or less.

The following is a draft of a possible problem description:

The Least Common Multiple or LCM of a set of numbers is a well-known concept. It can be defined as follows: The LCM of a set of numbers is the smallest positive integer which is exactly divisible by each of the numbers in the set. For example, LCM(14,20) = 140 and LCM(3,6,10) = 30. We can also define the LCM of a range of numbers e.g. LCM(2...5) = LCM(2,3,4,5) = 60 and LCM(10...15) = 60060. As the range of numbers increases the value of the LCM tends to increase rapidly. For example LCM(40...60) = 4224373219170545641200. Since we will be dealing with very big numbers we will give all of the results modulo 1000000007 (i.e. 10^9 + 7). So LCM(40...60) mod 1000000007 = 933314007.

In this problem you will be asked to find the LCM for each of about 4 different ranges of numbers. The numbers at the start and end of the range are both included in the LCM calculation. The range is likely to contain many numbers. Specifically, for a range from N1 to N2, N1 will not be larger than 2*N2/3. No number in any of the ranges will exceed 10 million and no range will contain more than 4 million numbers.

If your computer does not crash from the demands made on its resources and you get a correct solution after half a day of program execution time, then you deserve to claim the solution for sheer persistence! However, that defeats the object of the problem. You should look for an efficient solution. My experiments in Python (usually significantly slower than other languages) give times of just under 1 minute for what I think will be the most likely method. However, there is a better one, which executes about 100 times faster and has a significantly shorter and simpler program. My tests gave an average of 0.5 seconds for solving all 4 typical problems i.e. those generated by the problem setter routine. For those of you who are inclined to look for this fast solution, I will give one hint... (hint stolen by nasty admin)

Input data: The first line gives the number of ranges (typically 4). Each of the following lines contains two numbers separated by a space. These are the first and last numbers in the range.

Answer: This is a series of space-separated integers, giving the LCM values for each of the ranges, all calculated modulo 1000000007.

Example:

input:
4
10 15
40 60
5728 9708
6119950 9666068

60060 933314007 587266328 562476460
Rodion (admin)     2022-01-07 09:42:03
User avatar

Clive, Hi! Sorry for delay - there was Christmas this night on orthodox calendar :)

Just succeeded with approach you probably mention as "most likely" (though I guess there could be variations). At least I get the same result you provided :)

The problems sounds quite good (as the existing GCD & LCM is annoying since certain percentage of people use something like numpy.lcm(...) which makes problem to lose its small sense completely. This one should be nice "advanced" variant!

As about faster approach I didn't get the idea yet. Shall try to think a bit more, though it may happen I'll need your further hints or help...

gardengnome     2022-01-07 12:01:47
User avatar

Not sure about which approach is which, but for me the example runs in 0.5s with standard python and in 0.2s when making use of numpy (faster sieving).

Rodion (admin)     2022-01-07 13:03:47
User avatar

What I tried is described in wiki as (redacted by admin, check yourself) though of course it is easier to invent than to find in wiki (as happened to me).

For me it works for several minutes (in perl, so comparable to python).

I wonder which limit should we put on numbers. "half a day of program execution time" in Python may be say 30 minutes in some compiled language and thus probably we may want to increment values a bit further.

On the other hand of course we want "the clever method" to work below one second (when in generator).

gardengnome     2022-01-07 13:25:26
User avatar

Interesting. I use a somewhat related method. (thanks a lot for this valuable hint to me, but now I hide it - admin)...

Rodion (admin)     2022-01-07 13:31:23
User avatar

Ahm... they all are "somewhat related" due to prime factors etc but specific details of approach may ruing everything :) I suspect that's what CSFPython meant by not checking every number... got it... You Friends are too clever for me :)

Thanks for explanation, let me try this too and come back, perhaps it is a ready "checker" code then...

CSFPython     2022-01-07 13:44:32

Mathias has clearly used the efficient method (I wouldn't expect anything less) and the 0.5 second time for normal Python corresponds exactly with mine. However, I expect that a lot of other people will not see the efficient method without some hint. As for using compiled languages to get a reasonable time, part of the problem with a poor solution is the need to hold numbers in their exact form. This will give rise to storage issues in any language.

Rodion, I hope the Christmas celebrations went well.

Rodion (admin)     2022-01-07 17:55:44
User avatar

Oh, thanks - celebrations are calm and that's the better - tried to pick and watch some christmas movie - it appeared "Appartment" comedy-drama from 1960 - not quite related but nice :)

I at last succeeded in following the hints and php code runs similarly (reports 0.33 second on my meek laptop) - so everything is almost ready.

But what title would you prefer for the problem? Big LCM should be fine? or LCM of a Sequence?

CSFPython     2022-01-07 18:36:59

Rodion, I remember "The Apartment" with Jack Lemon very well and have seen it several times, but not for many years now.

I have no preference for the problem title so you should choose. Do you need anything else? It seems that you already have a checker.

Rodion (admin)     2022-01-07 23:18:18
User avatar

Clive, thanks - yep, with your hint elaborated by Mathias I was able to write checker myself (hopefully you don't mind - I'm a bit silly proud of being able to solve it even with hints, ha-ha) - just found it had subtle bug in cases when start of the range is divisible by test prime. Sorry for delay, was bit hard to concentrate on nailing it down due to some domestic chores :)

But for this reason I dared to include bit more test-cases.

Please have a look at the ready problem: LCM of a range - hopefully there are no other bugs of mine...

Thanks a lot for cooperation (you see, I myself usually can't come up with problems of "puzzling" kind)! As for the title - I decided to copy how you call it, this looks most clear...

P.S. I'll review the topic and wipe hints on solution, I think. Though it is a bit unjust as I myself used them :)

P.P.S. for comparison - on server generation runs for about 2 seconds - about 6 times slower than on my laptop... however it is not extremely noticeable among general pages lagging. Though this means increasing values is out of question (without precalc).

CSFPython     2022-01-07 23:56:13

Rodion, I have checked the problem with 3 separate runs and everything seems to be fine. The extra test cases don't add significantly to the solving time so they are a good idea.

Rodion (admin)     2022-01-08 08:07:01
User avatar

Clive, thanks for everything once more! Now only thing to be wished is to add some more cunning "recommendation" of next tasks on the successful submission, so that puzzles like this are reached earlier by people and not dangle in the bottom of the list :)

only to find that 3 more problems have appeared since I last logged in!

BTW you submitted them in about few mintes after login - though I suspect it's a kind of "master feature" - to attempt solving without testing and then submit everything in one shot :)

(as mentioned, probably, we have holidays between NY and Christmas which extend between Dec-31 and Jan-9 this time - so there is some time to spare on problems or improvements, no work, no classes... though I don't miss work as much as classes, ha-ha)

My suggestion is not as imaginative

To my taste your suggestions are generally much more puzzling and thus more valuable. Seemingly one needs to solve thousands of puzzles to build up the talent of inventing them... long way to learn yet :)

CSFPython     2022-01-08 10:49:27

Rodion, I didn't realise that anyone would be checking on the times when solutions are posted. When I returned to the site two days ago I noticed the 3 new problems immediately, because of the useful feature that lists them on the front page. Naturally I went straight to the problems and then wrote solutions for them. It was then necessary to log in so that the solutions could be posted. There was certainly no intention to give the impression that they had been solved in a ridiculously short time. The Turing problem and the line printer problem were both fairly simple and quick to code. The game took longer but not as long as I had expected because my first algorithm, which I wrote just to test the behaviour of the game, actually worked. I had expected it to fail and then to need to spend some time refining it.

Rodion (admin)     2022-01-13 08:47:47
User avatar

Ha-ha, seems the thought of using larger numbers wasn't naive :)

But currently I'm not sure I can do it without affecting generator execution time...

such solution

Quandray     2022-01-13 17:12:41
User avatar

I started to learn python in 2014, but never became proficient. Maybe I need to try again :-)

Rodion (admin)     2022-01-13 18:17:02
User avatar

Grae, I don't think this solution worked fast. Supposedly colleague just patiently waited...

Also range was luckily shorter than average...

But as for learning python I heartily understand! I dropped it couple of times but then some internal barrier was overcome and I found it is pretty simple... and handy in some situations :)

CSFPython     2022-01-16 15:13:37

I haven't seen the solution being referred to because I haven't got round to posting my own yet. However, I'm fairly sure that I know exactly what it must look like. All I can suggest is that the range should be kept close to 4 million (for the final set of data) and that the top end of the range should be close to 10 milllion. The size of the numbers involved is eye-watering so the solution time must be impressively long!

Rodion (admin)     2022-01-20 18:28:29
User avatar

Clive, thanks for suggestion, I edited checker so that the last example is about 8 mln range.

The solution by link is like this:

from math import gcd
from functools import reduce

def lcm(denominadores):
    respuesta=reduce(lambda a,b:((a*b)//gcd(a,b)),denominadores)
    print(int(respuesta)%1000000007)
Please login and solve 5 problems to be able to post at forum