k≤l的数字范围k..l之和等于(l×(l+1)-k×( k-1))/2。例如:1 .. 4等于(4×5-1×0)/2=(20-0)/2=10; 4 .. 5之和为(5×6-4×3)/2=(30-12)/2=9。
如果我们有一个总和S和一个偏移量k,我们可以因此找出总和是否存在一个l与:
2×S = l×(l+1)-k×(k-1)
0=l2+l-2×S-k×(k-1)
因此,我们可以用以下方法求解这个方程:
l=(-1 + √(1+8×S+4×k×(k-1)))/2
如果这是一个整数,则该序列存在。例如对于 S=9 和 k=4,我们得到:
l = (-1 + √(1+72+48))/2 = (-1 + 11)/2 = 10/2 = 5。
我们可以利用一些函数,比如Babylonian method [wiki] 来快速计算整数平方根:
squareRoot :: Integral t => t -> t
squareRoot n
| n > 0 = babylon n
| n == 0 = 0
| n < 0 = error "Negative input"
where
babylon a | a > b = babylon b
| otherwise = a
where b = quot (a + quot n a) 2
我们可以通过平方根来检查找到的根是否确实是精确的平方根,看看我们是否获得了原始输入。
现在我们有了这个,我们可以遍历序列的下界,并寻找上界。如果存在,我们返回序列,否则,我们尝试下一个:
decompose :: Int -> [[Int]]
decompose s = [ [k .. div (sq-1) 2 ]
| k <- [1 .. s]
, let r = 1+8*s+4*k*(k-1)
, let sq = squareRoot r
, r == sq*sq
]
因此,例如,我们可以通过以下方式获取项目:
Prelude> decompose 1
[[1]]
Prelude> decompose 2
[[2]]
Prelude> decompose 3
[[1,2],[3]]
Prelude> decompose 3
[[1,2],[3]]
Prelude> decompose 1
[[1]]
Prelude> decompose 2
[[2]]
Prelude> decompose 3
[[1,2],[3]]
Prelude> decompose 4
[[4]]
Prelude> decompose 5
[[2,3],[5]]
Prelude> decompose 6
[[1,2,3],[6]]
Prelude> decompose 7
[[3,4],[7]]
Prelude> decompose 8
[[8]]
Prelude> decompose 9
[[2,3,4],[4,5],[9]]
Prelude> decompose 10
[[1,2,3,4],[10]]
Prelude> decompose 11
[[5,6],[11]]
我们可以进一步限制范围,例如指定k,用:
decompose :: Int -> [[Int]]
decompose s = [ [k .. l ]
| k <- [1 .. div s 2 ]
, let r = 1+8*s+4*k*(k-1)
, let sq = squareRoot r
, r == sq*sq
, let l = div (sq-1) 2
, k < l
]
这给了我们:
Prelude> decompose 1
[]
Prelude> decompose 2
[]
Prelude> decompose 3
[[1,2]]
Prelude> decompose 4
[]
Prelude> decompose 5
[[2,3]]
Prelude> decompose 6
[[1,2,3]]
Prelude> decompose 7
[[3,4]]
Prelude> decompose 8
[]
Prelude> decompose 9
[[2,3,4],[4,5]]
Prelude> decompose 10
[[1,2,3,4]]
Prelude> decompose 11
[[5,6]]