BOJ: 1024

문제

N과 L이 주어질 때, 합이 N이면서, 길이가 적어도 L인 가장 짧은 연속된 음이 아닌 정수 리스트를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N과 L이 주어진다. N은 1,000,000,000보다 작거나 같은 자연수이고, L은 2보다 크거나 같고, 100보다 작거나 같은 자연수이다.

출력

만약 리스트의 길이가 100보다 작거나 같으면, 연속된 수를 첫째 줄에 공백으로 구분하여 출력한다. 만약 길이가 100보다 크거나 그러한 수열이 없을 때는 -1을 출력한다.


Solution

문제의 답이 start에서 start + size - 1까지의 합이라고 가정하면 아래와 같은 수식이 성립한다.

$$
\begin{aligned}
N&=\Sigma_{j=0}^{size}(start+j)\newline&=start+(start+1)+\cdots+(start+size-1)
\end{aligned}
$$

그럼 이 식을 아래와 같이 전개할 수 있다.

$$
\begin{gathered}
start+(start+1)+\cdots+(start+size-1)\newline
=start\times size+\frac{size\times(size-1)}{2}\newline
(\because\Sigma_{i=0}^{size-1}i=\frac{size\times(size-1)}{2})
\end{gathered}
$$

$\frac{size\times(size+1)}{2}$을 좌항으로 이동시키면 아래와 같이 전개된다.

$$ N-\frac{size\times(size-1)}{2}=start\times size $$

이때 좌항은 정수와 정수의 뺄셈이므로 정수이고, 우항은 필연적으로 정수이다.
따라서 start % size == 0이다.

$start\times size=M$이라 가정하면 $M\geq0$이다. ($\because start\geq0,\ size\geq2$)
따라서 M >= 0이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import "fmt"

func main() {
var N, L int
fmt.Scan(&N, &L)

flag := true
for size := L; size < 101; size++ {
M := N - size*(size-1)/2
if M%size == 0 && M >= 0 {
start := M / size
for j := start; j < start+size; j++ {
fmt.Print(j, " ")
}
flag = false
break
}
}
if flag {
fmt.Print(-1)
}
}