티스토리 뷰

Boj

[12797] 연금술

jwvg0425 2020. 10. 23. 00:41

https://www.acmicpc.net/problem/12797

 

12797번: 연금술

첫 줄에 정수 n과 m(1 ≤ n ≤ 109, 1 ≤ m ≤ 103)이 공백으로 구분되어 두고 주어진다. 다음 줄에 a1, a2, ..., am (1 ≤ ai ≤ 109)이 공백으로 구분되어 주어진다.

www.acmicpc.net

고생 고생 끝에 겨우 풀었다. 정리해둘만한 내용이 많은 문제인 것 같아서 풀이를 기록해 둠.

 

우선 점화식부터 유도해보자. DP(n,m)1m 번 까지의 재료를 써서 n 개 조합할 때 만들 수 있는 완성품 품질의 총합이라고 정의한다. 이 경우 DP(n,m)의 점화식은 다음과 같이 세울 수 있다.

 

DP(n,m)=amDP(n1,m)+DP(n,m1)

 

 m 번 재료를 한 번 더 포함 시킬지 / 더이상 m 번 재료를 포함시키지 않고 m1번 재료를 포함시키는 단계로 넘어갈 건지 고르는 것이므로 비교적 직관적으로 점화식을 유도할 수 있다.

 

 이제 이 점화식을 조금 더 풀어 써보면, DP(n,m1)=am1DP(n1,m1)+DP(n,m2) 이고, 다시 DP(n,m2)=am2DP(n1,m2)+DP(n,m3) 이고, ... 이 형태가 반복되므로 식을 아래와 같이 정리할 수 있다.

 

DP(n,m)=nk=1akDP(n1,k)

 

이런 점화식은 각 행에 대해 계수를 행렬로 분리하고 보면 행렬 곱 형태로 나타낼 수 있다. 맨 첫번째 행이 a1,0,,0,0 , 그 다음 행이 a1,a2,,0,0, 다시 그 다음 행이 a1,a2,a3,,0,0, ... 형태로 이루어진 행렬을 생각해보자. 즉, i번째 행은 맨 처음 i 열에는 ai가 적혀 있고, 그 다음 열들에 대해서는 0이 적혀 있다. 그러니까 삼각 행렬의 형태를 가진다. 이 행렬을 A라고 하고 다음 식을 생각해보자.

 

A[DP(n1,1)DP(n1,2)DP(n1,m)]

 

행렬 A에 DP(n1,1) 부터 DP(n1,m) 까지 값을 순서대로 나열한 열벡터를 곱한 것이다. 이 때 행렬 곱셈식을 위에 적은 점화식을 바탕으로 정리하면 이 곱셈의 결과는

 

[DP(n,1)DP(n,2)DP(n,m)]

 

이 된다. 즉, 곱셈을 하고 나면 벡터의 모든 i번째 위치 값에 대해 DP(n1,i)DP(n,i)로 바뀐다.

 

이렇게 행렬 곱 형태로 나타내면, 행렬 곱을 n번 하는 건 행렬의 빠른 거듭 제곱을 이용해 O(logN) 번의 행렬 곱만으로 계산할 수 있다. 행렬 곱은 한 번에 O(M3)의 시간이 걸리므로, 총 시간 복잡도 O(M3logN)에 문제를 해결할 수 있다. 원래의 O(NM) 시간 복잡도에 비해 빠르긴 하나 이 방법으로도 해당 문제를 풀기에는 충분히 빠르지 못하다.

 

 여기서 속도를 최적화하기 위해 행렬의 대각화를 이용한다. 행렬의 대각화는 어떤 행렬 A가 있을 때, D=Q1AQ 이면서 D가 대각행렬(주 대각선 외에는 전부 값이 0인 행렬)임을 만족하는 D를 구하는 것을 말한다. 행렬을 대각화할 경우 우리가 구하고자 하는 식은 QDnQ1B 가 된다. 여기서 DnD가 대각행렬이므로 O(MlogN) 시간에 구할 수 있다.

 

 비슷하게, D가 대각행렬이므로 QDn 을 구하는 과정은 O(M2) 시간에 계산할 수 있다. B가 벡터이므로 Q1B 역시 O(M2) 시간에 구할 수 있고, 이 둘을 다시 곱하는데에도 O(M2)의 시간이면 충분하므로 전체 시간복잡도 O(M2)에 문제를 해결할 수 있다.

 

 이제 남은 과정은 행렬을 대각화할 수 있는지 여부 및 대각화하는 방법을 찾는 것이다. 이 때, 우리가 만든 행렬은 삼각 행렬이며 주 대각선의 모든 수가 서로 다르다(문제에서 ai는 전부 서로 다른 수라고 명시했기 때문). 주 대각선의 모든 수가 서로 다른 삼각 행렬은 항상 대각화가 가능하다. 삼각행렬이기 때문에 주 대각선에 위치한 수가 전부 해당 행렬의 고유값이 되고, 이 수들이 전부 서로 다르므로 m개의 고유값이 존재한다. 고유값이 주 대각선에 위치한 수와 일치하므로, 대각 행렬 D의 주 대각선에는 a1,a2,,am이 존재하게 된다. 이제, 행렬 QQ1만 구하면 문제를 해결할 수 있다.

 

 이 때 주어진 행렬의 모든 고유벡터를 구하는 건(그러니까 행렬 Q를 구하는 건) 비교적 간단하게 O(M2)에 수행할 수 있다.  행렬 Q의 주 대각선을 모두 1로 채우고, 고유벡터를 구하기 위해 행렬 A 에서 각각의 고유값 ai를 뺀 경우에 대해 조건을 만족하게끔 Q의 값을 채운다고 생각해보자. 쭉 나열해놓고 보면, 바로 Q의 값을 채워넣을 수 있는 칸이 항상 존재한다. 이 칸들을 채우는 식이 어떻게 되는지 정리해보면 규칙성이 존재해서 Q 행렬을 O(M2) 시간에 구할 수 있다. 어떤 규칙성이 있는지는 식을 적기가 너무 번거로워서 생략. 직접 유도해보면 어렵지 않게 찾을 수 있다.

 

 이제 행렬 Q1을 구하는게 문제인데, 이 역행렬을 그냥 계산하려고 하면 식이 깔끔하게 떨어지지 않는다. 여기서는 Q1이 궁금한게 아니라 Q1B 가 궁금하다는 것에 착안하자. Q1B=X라고 하면, B=QX를 만족한다. Q 행렬은 계산 가능하며 삼각 행렬이다. 따라서 삼각 행렬의 맨 아래칸(1칸 밖에 없는 위치)부터 시작해서 순서대로 X의 각 변수를 확정지어나가면 O(M2) 시간에 Q1B도 계산 가능하다. 따라서 전체 시간 복잡도 O(M2)에 문제를 풀 수 있다.

 

 선형대수를 원래 잘 못하기도 하고 관련 문제를 풀어본 적이 거의 없다시피해서 정말 한참을 고생해서 풀었다. 덕분에 선형대수와 관련해서 많이 배운 것 같다..

'Boj' 카테고리의 다른 글

USACO Platinum - 4  (0) 2020.09.01
USACO Platinum - 3  (0) 2020.09.01
USACO Platinum - 2  (0) 2020.08.31
USACO Platinum - 1  (0) 2020.08.30
[16663] Distance Sum  (0) 2020.04.08
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함