|
@@ -0,0 +1,168 @@
|
|
|
|
|
+local UPPER_BOUND = 5000000
|
|
|
|
|
+local PREFIX = 32338
|
|
|
|
|
+
|
|
|
|
|
+local Node = {}
|
|
|
|
|
+function Node:new()
|
|
|
|
|
+ local obj = {}
|
|
|
|
|
+ setmetatable(obj, self)
|
|
|
|
|
+ self.__index = self
|
|
|
|
|
+ obj.children = {}
|
|
|
|
|
+ obj.terminal = false
|
|
|
|
|
+ return obj
|
|
|
|
|
+end
|
|
|
|
|
+
|
|
|
|
|
+local Sieve = {}
|
|
|
|
|
+function Sieve:new(limit)
|
|
|
|
|
+ local obj = {}
|
|
|
|
|
+ setmetatable(obj, self)
|
|
|
|
|
+ self.__index = self
|
|
|
|
|
+ obj.limit = limit
|
|
|
|
|
+ obj.prime = {}
|
|
|
|
|
+ for i = 0, limit do
|
|
|
|
|
+ obj.prime[i] = false
|
|
|
|
|
+ end
|
|
|
|
|
+ return obj
|
|
|
|
|
+end
|
|
|
|
|
+
|
|
|
|
|
+function Sieve:to_list()
|
|
|
|
|
+ local result = {2, 3}
|
|
|
|
|
+ for p = 5, self.limit do
|
|
|
|
|
+ if self.prime[p] then
|
|
|
|
|
+ table.insert(result, p)
|
|
|
|
|
+ end
|
|
|
|
|
+ end
|
|
|
|
|
+ return result
|
|
|
|
|
+end
|
|
|
|
|
+
|
|
|
|
|
+function Sieve:omit_squares()
|
|
|
|
|
+ local r = 5
|
|
|
|
|
+ while r * r < self.limit do
|
|
|
|
|
+ if self.prime[r] then
|
|
|
|
|
+ local i = r * r
|
|
|
|
|
+ while i < self.limit do
|
|
|
|
|
+ self.prime[i] = false
|
|
|
|
|
+ i = i + r * r
|
|
|
|
|
+ end
|
|
|
|
|
+ end
|
|
|
|
|
+ r = r + 1
|
|
|
|
|
+ end
|
|
|
|
|
+ return self
|
|
|
|
|
+end
|
|
|
|
|
+
|
|
|
|
|
+function Sieve:step1(x, y)
|
|
|
|
|
+ local n = (4 * x * x) + (y * y)
|
|
|
|
|
+ if n <= self.limit and (n % 12 == 1 or n % 12 == 5) then
|
|
|
|
|
+ self.prime[n] = not self.prime[n]
|
|
|
|
|
+ end
|
|
|
|
|
+end
|
|
|
|
|
+
|
|
|
|
|
+function Sieve:step2(x, y)
|
|
|
|
|
+ local n = (3 * x * x) + (y * y)
|
|
|
|
|
+ if n <= self.limit and n % 12 == 7 then
|
|
|
|
|
+ self.prime[n] = not self.prime[n]
|
|
|
|
|
+ end
|
|
|
|
|
+end
|
|
|
|
|
+
|
|
|
|
|
+function Sieve:step3(x, y)
|
|
|
|
|
+ local n = (3 * x * x) - (y * y)
|
|
|
|
|
+ if x > y and n <= self.limit and n % 12 == 11 then
|
|
|
|
|
+ self.prime[n] = not self.prime[n]
|
|
|
|
|
+ end
|
|
|
|
|
+end
|
|
|
|
|
+
|
|
|
|
|
+function Sieve:loop_y(x)
|
|
|
|
|
+ local y = 1
|
|
|
|
|
+ while y * y < self.limit do
|
|
|
|
|
+ self:step1(x, y)
|
|
|
|
|
+ self:step2(x, y)
|
|
|
|
|
+ self:step3(x, y)
|
|
|
|
|
+ y = y + 1
|
|
|
|
|
+ end
|
|
|
|
|
+end
|
|
|
|
|
+
|
|
|
|
|
+function Sieve:loop_x()
|
|
|
|
|
+ local x = 1
|
|
|
|
|
+ while x * x < self.limit do
|
|
|
|
|
+ self:loop_y(x)
|
|
|
|
|
+ x = x + 1
|
|
|
|
|
+ end
|
|
|
|
|
+end
|
|
|
|
|
+
|
|
|
|
|
+function Sieve:calc()
|
|
|
|
|
+ self:loop_x()
|
|
|
|
|
+ return self:omit_squares()
|
|
|
|
|
+end
|
|
|
|
|
+
|
|
|
|
|
+local function generate_trie(l)
|
|
|
|
|
+ local root = Node:new()
|
|
|
|
|
+ for _, el in ipairs(l) do
|
|
|
|
|
+ local head = root
|
|
|
|
|
+ -- attempt to call a nil value (method 'split')
|
|
|
|
|
+ -- how to fix? use string.split
|
|
|
|
|
+ el = tostring(el)
|
|
|
|
|
+ for i=1, #el do
|
|
|
|
|
+ local ch = el:sub(i, i)
|
|
|
|
|
+ if not head.children[ch] then
|
|
|
|
|
+ head.children[ch] = Node:new()
|
|
|
|
|
+ end
|
|
|
|
|
+ head = head.children[ch]
|
|
|
|
|
+ end
|
|
|
|
|
+ head.terminal = true
|
|
|
|
|
+ end
|
|
|
|
|
+ return root
|
|
|
|
|
+end
|
|
|
|
|
+
|
|
|
|
|
+local function find(upper_bound, prefix_)
|
|
|
|
|
+ local primes = Sieve:new(upper_bound):calc()
|
|
|
|
|
+ local str_prefix = tostring(prefix_)
|
|
|
|
|
+ local head = generate_trie(primes:to_list())
|
|
|
|
|
+ for i=1, #str_prefix do
|
|
|
|
|
+ local ch = str_prefix:sub(i, i)
|
|
|
|
|
+ head = head.children[ch]
|
|
|
|
|
+ if head == nil then
|
|
|
|
|
+ return nil
|
|
|
|
|
+ end
|
|
|
|
|
+ end
|
|
|
|
|
+
|
|
|
|
|
+ local queue, result = {{head, str_prefix}}, {}
|
|
|
|
|
+ while #queue > 0 do
|
|
|
|
|
+ local tuple = table.remove(queue)
|
|
|
|
|
+ local top, prefix = tuple[1], tuple[2]
|
|
|
|
|
+ if top.terminal then
|
|
|
|
|
+ table.insert(result, tonumber(prefix))
|
|
|
|
|
+ end
|
|
|
|
|
+ for ch, v in pairs(top.children) do
|
|
|
|
|
+ table.insert(queue, 1, {v, prefix .. ch})
|
|
|
|
|
+ end
|
|
|
|
|
+ end
|
|
|
|
|
+
|
|
|
|
|
+ table.sort(result)
|
|
|
|
|
+ return result
|
|
|
|
|
+end
|
|
|
|
|
+
|
|
|
|
|
+local function verify()
|
|
|
|
|
+ local left = {2, 23, 29}
|
|
|
|
|
+ local right = find(100, 2)
|
|
|
|
|
+ if #left ~= #right then
|
|
|
|
|
+ print("length not equal")
|
|
|
|
|
+ os.exit(1)
|
|
|
|
|
+ end
|
|
|
|
|
+ for i, v in ipairs(left) do
|
|
|
|
|
+ if v ~= right[i] then
|
|
|
|
|
+ print(string.format("%s != %s", v, right[i]))
|
|
|
|
|
+ os.exit(1)
|
|
|
|
|
+ end
|
|
|
|
|
+ end
|
|
|
|
|
+end
|
|
|
|
|
+
|
|
|
|
|
+verify()
|
|
|
|
|
+local results = find(UPPER_BOUND, PREFIX)
|
|
|
|
|
+local expected = {323381, 323383, 3233803, 3233809, 3233851, 3233863, 3233873, 3233887, 3233897}
|
|
|
|
|
+
|
|
|
|
|
+for i, v in ipairs(results) do
|
|
|
|
|
+ if v ~= expected[i] then
|
|
|
|
|
+ print(string.format("%s != %s", v, expected[i]))
|
|
|
|
|
+ os.exit(1)
|
|
|
|
|
+ end
|
|
|
|
|
+end
|
|
|
|
|
+
|