my solution in Java
import java.io.*;
import java.util.*;
public class ProblemF {
public static void main(String[] args) throws Exception {
BufferedReader fileIn = new BufferedReader(new FileReader("f.in"));
String line = null;
while ((line = fileIn.readLine()) != null) {
int number = Integer.parseInt(line);
if (number <= 0 || number >= 100000000) {
break;
}
System.out.println(number +" : "+ getOrderedPairs(number));
}
}
public static String getOrderedPairs(int number) {
StringBuffer buff = new StringBuffer();
int pairCount = 0;
for (int i = 1; i <= number; i++) {
for (int j = i; j <= number; j++) {
int sum = getSummation(i, j);
if (sum == number) {
pairCount++;
buff.append(" ("+ i +","+ j +")");
break;
} else if (sum > number) {
break;
}
}
}
buff.insert(0, pairCount +" :");
return buff.toString();
}
public static int getSummation(int tempA, int tempB) {
int a = tempA - 1;
int b = tempB;
int sumB = ((b * (b + 1)) / 2);
int sumA = ((a * (a + 1)) / 2);
return sumB - sumA;
}
(defun func (string &optional acc)
(if lst
(loop for x from 0 to (1- (length array))
for i in array do
(if (eq i ":")
(func (cdr lst) (cons (aref (1- x) array) acc))))
acc))
Kinda, that should PROBABLY do it, I haven't tested it though.
At first I wrote a naive solution like you, but noticed it was SLOW AS FUCK even when I cranked up the optimization settings:
(asdf:oos 'asdf:load-op '#:iterate)
(use-package '#:iterate)
(declaim (optimize (speed 3) (safety 0)))
(declaim (inline sum-to))
(defun sum-to (a b)
(declare (fixnum a b))
; (loop for i from a to b sum i) ; naive/slow
(the fixnum (/ (- (* b (1+ b)) (* a (1- a))) 2))
;(the fixnum (/ (* (1+ (- b a)) (+ b a)) 2))
)
;; too slow O(n*n), starts being unusable at ~10^6, when it takes longer than a minute per number
(defun find-all-sums (x)
(iter outer (for i from 1 to x)
(iter (for j from i to x)
(when (= (sum-to i j) x)
(in outer (collect (print (list i j))))))))
So I wrote this instead:
;; instead we use some math and make it O(n)
(defun find-all-sums (x)
(sort
(remove-duplicates
(iter (with 2x = (* 2 x))
(for i from x downto 1)
(for (values div mod) = (truncate 2x i))
(when (zerop mod)
(let* ((a (/ (1- (+ div i)) 2))
(b (- (max div i) a)))
(collect (list b a)))))
:key #'first)
#'< :key #'first))
Let's test it on the highest number:
CL-USER> (time (find-all-sums 99999999))
Evaluation took:
1.469 seconds of real time
1.468750 seconds of total run time (1.468750 user, 0.000000 system)
100.00% CPU
3,541,887,882 processor cycles
0 bytes consed
check x
| x <= 0 || x > 100000000 = error "you mena haskal?"
| otherwise = x
orderedPairs n = (n, [(a,b) | a <- [1..n], b <- [a..n], sum [a..b] == n])
format (x,ps) = show x ++ " : " ++ show (length ps) ++ " : " ++ (unwords . map (\(a,b) -> "(" ++ show a ++ "," ++ show b ++ ")")) ps
Name:
Anonymous2011-04-13 20:23
open System
let orderedPairs x = List.rev [ for b = x downto 1 do
for a = b downto 1 do
if (List.sum [a..b]) = x then yield (a, b) ]
let numbers =
let rec getNumbers x =
if (0 < x) && (x < 100000000) then x :: getNumbers(int(Console.ReadLine()))
else []
getNumbers(int(Console.ReadLine()))
let rec orderedPairsString orderedPairsX =
match orderedPairsX with
| (a, b) :: t -> "(" + string(a) + ", " + string(b) + ") " + orderedPairsString(t)
| [] -> ""
in brainfuck ++++++++[->++++<]>>>++++++[<++++++>-]<++++[->+>
+>+<<<]>>++++>+>,.<<<<.>>>>>++++++++[-<------>]
<[->+>>>+>>>+<<<<<<<]+>+<[>[->+>+<<]>>>[->+>+<<
]>[-<+<+>>]<<+<[-<+>>>>>-<<<<]>[->>>[-<+>>>+<<]
<[->+<]<<]>>>[-]>[->-->+<<]+>[[-]<[-]>]<[[-]+++
+++++++++[-<<<++++<<<++++>>>>>>]<<<<<<<<<<.>>>>
+.-<<<.>>>>>>.<<<<<.<<<.>>>>>>>>>>>++++++++++++
[-<<<----<<<---->>>>>>][-]]>>[-<<+>>]<<<<<<<<->
+<[->[-]>+<<]>>[-<<+>>]<[[-]>>->+<[->[-]>+<<]>>
[-<<+>>]<[[-]<<<<<[-]>>>>>]<[-<<<+>>>>+<]>[-<+>
]<<<]<<] http://codepad.org/NdgW7mgP
well, it actually solves for only a single digit but algorithm is correct. It just requires a little extra work for inputting and printing multiple digit numbers
Name:
Anonymous2011-04-13 21:45
What I came up with:
tr :: Int -> Int
tr n = n * (n-1) `div` 2
untr :: Int -> Int
untr n' = let n = fromIntegral n' in ceiling $ sqrt (n*2)
f :: Int -> [(Int, Int)]
f n = [(a,b) | b <- [2..n], let b' = tr (b+1), let a' = (b'-n), let a = untr a', tr a == a']
main = do x <- readLn
print $ f x
main
Not as good as some of the solutions here, but it solves the biggest case in half the needed time.
let orderedPairs x =
[ for b = 1 to x do
let rec checkFrom(n) =
if n < 1 then []
elif sumAtoB(n, b) > x then []
elif sumAtoB(n, b) = x then (n, b) :: checkFrom(n - 1)
else checkFrom(n - 1)
yield checkFrom(b) ] |> List.concat
let numbers =
let rec getNumbers x =
if (0 < x) && (x < 100000000) then x :: getNumbers(int(Console.ReadLine()))
else []
getNumbers(int(Console.ReadLine()))
let rec orderedPairsString orderedPairsX =
match orderedPairsX with
| (a, b) :: t -> "(" + string(a) + ", " + string(b) + ") " + orderedPairsString(t)
| [] -> ""