랜덤 PS일지 (1)
중간고사 끝난 것을 기념으로! 근데 첫 문제는 시험 전날에 공부하기 싫어서 잡았다.
30323번
- BOJ 30323: Exponentiation
주어진 $\alpha = x + x^{-1}$와 $\beta$에 대하여 $x^\beta + x^{-\beta} \pmod m$을 구하면 된다.
먼 옛날 곱셈 공식의 변형
\[x^2 + \frac{1}{x^2} = \left( x + \frac{1}{x} \right)^2 - 2\]을 공부하던 기억을 떠올리며…
$\beta$가 짝수인 경우에는 쉽게 처리할 수 있다.
\[x^\beta + x^{-\beta} = (x^{\beta/2} + x^{-\beta/2})^2 - 2.\]홀수인 경우에는1 지수의 크기를 절반으로 줄이는 것이 핵심일테니,
\[x^\beta + x^{-\beta} = \left( x^{\frac{\beta+1}{2}} + x^{-\frac{\beta+1}{2}}\right)\left( x^{\frac{\beta-1}{2}} + x^{-\frac{\beta-1}{2}}\right) - (x + x^{-1})\]를 생각하면 된다. 같은 지수에 대해서 여러 번 계산을 할 수도 있으므로, 결과를 저장해뒀다가 꺼내서 쓰도록 하자.
12728, 12925번
두 문제가 같은 문제이다. $(3 + \sqrt{5})^n$의 정수부분의 마지막 $3$자리를 구하면 된다.
중학교 시절 에이급 수학에서 $(3 + 2\sqrt{2})^5$의 정수부분을 구하라는 문제를 봤었는데 이 때 사용했던 아이디어가 켤레무리수를 생각하는 것이었다. 비슷한 아이디어를 2017학년도 서울대학교 공과대학 수시 일반 심층 면접에서도 $(2 + \sqrt{5})^n$이 나와 사용했었다. 그리고…
정리. $\alpha = 3 + \sqrt{5}$, $\beta = 3 - \sqrt{5}$ 일 때, $\alpha^n + \beta^n \in \mathbb{N}$.2
여기서 핵심은 $0 < \beta < 1$ 임을 이용하는 것이다. 따라서, $\alpha^n$의 정수부분은 $\alpha^n + \beta^n - 1$이 된다. 이제 $\alpha^n + \beta^n$만 구하면 된다. 근과 계수의 관계를 이용하면 수열 $s_n = \alpha^n + \beta^n$에 대한 귀납적 정의를 얻을 수 있다.
$n$이 크기 때문에 계산은 행렬을 빠르게 거듭제곱하는 형태를 사용하면 된다.
4215번
- BOJ 4215: To Add or to Multiply
우선 주어진 범위 내에서 가능한 곱셈의 횟수는 최대 $29$번이다. ($2^{30} > 10^9$) 그러므로 모든 $m$에 대해 조사할 시간은 충분하다.
곱셈을 $g$번 한다고 가정하고, 이 때 $0, \dots, g$ 번째 덧셈 횟수를 $h_i$라 하자. 그렇다면 입력이 $x$일 때, 우리가 생성한 프로그램의 최종 값은
\[x \cdot m^g + a \sum_{i=0}^g m^{g-i} h_i\]가 된다. 입력 범위 $[p, q]$를 $[r, s]$로 보내야 하므로, 부등식을 세워보면
\[\tag{1} a\sum_{i=0}^g m^{g-i} h_i \in \left[ r - p \cdot m^g, s - q\cdot m^g \right]\]여야 함을 알 수 있다. 그러면 이제 프로그램의 길이를 최소화 해야하는데, 길이가 $\sum_{i=0}^g h_i + g$ 이므로 $h_i$의 합을 최소화하는 방향으로 생각해본다. 좌변의 식을 조금 풀어서 써보면
\[a\sum_{i=0}^g m^{g-i} h_i =(am^g)h_0 + (am^{g-1})h_1 + \cdots + (a)h_g\]이므로 $\sum h_i$를 최소화 하려면 $h_0$부터 $h_g$까지 순서대로 잡아주면 된다. 이 때 $(1)$의 범위를 만족해야 하므로, 범위를 만족하는 최소의 $h_0$가 잡히면 바로 끝. 만약 불가능하다면 $r - p\cdot m^g$를 넘지 않는 최대의 $h_0$를 잡고 이번에는 구간 양 끝에서 $am^gh_0$를 뺀 뒤 같은 방법으로 $h_1$을 잡으면 된다.
모든 가능한 프로그램의 후보를 얻었다면, 가장 짧은 것을 찾고 사전 순으로 제일 먼저 오는 것을 찾으면 된다. 사전 순 정렬의 경우 귀납적으로 생각하면 쉽게 구현할 수 있다. 앞에서부터 연산의 종류와 횟수를 비교하면 된다.