```Christian Neukirchen <chneukirchen / gmail.com> wrote:
> #!ruby
> =begin
>
> The Quiz was real fun and I spent quite a lot of time on it.  Below
> source is rather easy, but believe me I tried lots of different ways
> (such as dynamic binary knapsacks etc.), most of them suck because they
> need to many method calls.

Same here - I tried a bunch of stuff, but the code ended up being rather
slow, so I discarded it. It's still rather slow :(

N = ARGV[0].to_i

# precalculate the list of primes

def primes_to(n)
sieve = (0..n).to_a
2.upto(n) {|i|
next unless sieve[i]
(i*i).step(n, i) {|j| sieve[j] = nil}
}
sieve[2..-1].compact
end

PRIMES = primes_to(N)

# helper method
class Array
def bsearch(n)
i = 0
j = size - 1
k = (i+j)/2
while i < k
if at(k) > n
j = k
elsif at(k) < n
i = k
else
return k
end
k = (i+j)/2
end
return i
end
end

# factorisation routines - find the prime factors, then combine them to get a
# list of all factors

def prime_factors(x)
pf = Hash.new {|h, k| h[k] = 0}
PRIMES.each {|p|
break if p > x
while x % p == 0
pf[p] += 1
x /= p
end
}
pf
end

def expand_factors(f, pf)
return f if pf.empty?
p, n = pf.shift
powers = [p]
(n-1).times { powers << p * powers[-1] }
g = f.dup
powers.each {|i| f.each {|j| g << i*j } }
expand_factors(g, pf)
end

def factors(n)
a = expand_factors([1], prime_factors(n)).sort
a.pop
a
end

# and finally, the weirdness test

def weird?(n)
fact = factors(n)
#
# test for abundance (sum(factors(n)) > n)
sum = fact.inject {|a, i| a+i}
return false if sum < n # weird numbers are abundant

# now the hard part
partials = [0]

fact.each {|f|
if sum < n
# discard those partials that are lower than the sum of all remaining
# factors
i = partials.bsearch(n-sum)
return false if partials[i] == (n-sum)
partials = partials[(i+1)..-1]
end

sum -= f # sum of all remaining factors
temp = []

partials.each {|p|
j = f + p
break if j > n
l = n - j
next if l > sum
return false if (j == n) or (l == sum)
temp << j
}

# handwriting a merge sort didn't help :-/
partials = partials.concat(temp).sort.uniq
}

return true
end

def all_weird(n)
weird = []
# odd numbers are not weird (unproven but true for all n < 10^17)
2.step(n, 2) {|i| weird << i if weird?(i) }
weird
end

require 'benchmark'

Benchmark.bm(10) {|x|
[1000,10000,20000].each {|n|
x.report("#{n}") {p all_weird(n)}
}
}

martin

```