# Paste: Project Euler #50

Author: ElasticDog factor Thu, 20 Nov 2008 06:47:56
Plain Text |
```! Copyright (c) 2008 Aaron Schaefer.
USING: arrays kernel locals math math.primes sequences ;
IN: project-euler.050

! http://projecteuler.net/index.php?section=problems&id=50

! DESCRIPTION
! -----------

! The prime 41, can be written as the sum of six consecutive primes:

!     41 = 2 + 3 + 5 + 7 + 11 + 13

! This is the longest sum of consecutive primes that adds to a prime below
! one-hundred.

! The longest sum of consecutive primes below one-thousand that adds to a
! prime, contains 21 terms, and is equal to 953.

! Which prime, below one-million, can be written as the sum of the most
! consecutive primes?

! SOLUTION
! --------

! 1) Create an sequence of all primes under 1000000.
! 2) Start summing elements in the sequence until the next number would put you
!    over 1000000.
! 3) Check if that sum is prime, if not, subtract the last number added.
! 4) Repeat step 3 until you get a prime number, and store it along with the
!    how many consecutive numbers from the original sequence it took to get there.
! 5) Drop the first number from the sequence of primes, and do steps 2-4 again
! 6) Compare the longest chain from the first run with the second run, and store
!    the longer of the two.
! 7) If the sequence of primes is still longer than the longest chain, then
!    repeat steps 5-7...otherwise, you've found the longest sum of consecutive
!    primes!

<PRIVATE

:: sum-upto ( seq limit -- length sum )
0 seq [ + dup limit > ] find
[ swapd - ] [ drop seq length swap ] if* ;

: pop-until-prime ( seq sum -- seq prime )
over length 0 > [
[ unclip-last-slice ] dip swap -
dup prime? [ pop-until-prime ] unless
] [
2drop { } 0
] if ;

! a pair is { length of chain, prime the chain sums to }

: longest-prime ( seq limit -- pair )
dupd sum-upto dup prime? [
2array nip
] [
[ length ] dip 2array
] if ;

: longest ( pair pair -- longest )
2dup [ first ] bi@ > [ drop ] [ nip ] if ;

: continue? ( pair seq -- ? )
[ first ] [ length 1- ] bi* < ;

: (find-longest) ( best seq limit -- best )
[ longest-prime longest ] 2keep 2over continue? [
[ rest-slice ] dip (find-longest)
] [ 2drop ] if ;

: find-longest ( seq limit -- best )
{ 1 2 } -rot (find-longest) ;

: solve ( n -- answer )
[ primes-upto ] keep find-longest second ;

PRIVATE>

: euler050 ( -- answer )
1000000 solve ;

! [ euler050 ] 100 ave-time
! 291 ms run / 20.6 ms GC ave time - 100 trials

MAIN: euler050```