1. 문제
E - Geometric Progression (atcoder.jp)
E - Geometric Progression
AtCoder is a programming contest site for anyone from beginners to experts. We hold weekly programming contests online.
atcoder.jp
정수 A,X,M이 주어질 때, X−1∑k=0Ak를 구하는 아주 간단한 문제
2. 풀이1
이미 재귀로 푸는 방법을 배운적 있다
컴퓨터가 등비수열의 합을 구하는 방법 (tistory.com)
컴퓨터가 등비수열의 합을 구하는 방법
1. 문제 15712번: 등비수열 (acmicpc.net) 15712번: 등비수열 첫째 줄에 a, r, n, mod가 공백으로 구분되어 주어진다. a, r, n, mod는 모두 1보다 크거나 같고, 109보다 작거나 같은 자연수이다. www.acmicpc.net 초항
deepdata.tistory.com
3. official editorial
editorial에서 제공하는 방법을 보면...
an=n−1∑k=0Ak이라고 하자.
그러면 a0=0, an+1=Aan+1이다.
이를 행렬로 표현하면 다음과 같다
(an+11)=(A101)(an1)
따라서 n = 0이면...
(a11)=(A101)(01)
n=1이면...
(a21)=(A101)(a11)
위의 식을 그대로 대입하면 다음을 얻는다..
(a21)=(A101)2(01)
구하고자 하는건 aX=∑X−1k=0Ak이므로, n = X가 될 때까지 반복해서 곱하면..
(aX1)=(A101)X(01)
따라서 (A101)X만 구할 수 있다면, 원하는 값을 구할 수 있게 된다
--------------------------------------------------------------------------------------------------------------------------
먼저 두 행렬의 곱은 어떻게 구할 수 있을까
A,B의 곱 C의 ij번째 원소는... 모든 k = 1,2,...에 대하여.. a의 ik번째 원소와 b의 kj번째 원소의 곱의 합이다.
cij=∑kaikbkj
mod연산의 성질로부터, 곱셈한 결과를 계속 mod연산으로 나눠서 더해준다.
def matrix_multiplication(a,b,n,mod):
mul = [[0] * n for _ in range(n)]
for i in range(n):
for j in range(n):
for k in range(n):
mul[i][j] += a[i][k] * b[k][j]
mul[i][j] %= mod
return mul
다음 행렬의 거듭제곱은 어떻게 만들 수 있을까..?
분할정복을 이용한 거듭제곱 코드를 다시 살펴보자
def power(a,n):
result = 1
while n:
if n % 2 == 1:
result *= a
a *= a
n //= 2
return result
처음에 result = 1을 초기화하고, n이 1 이상일 때까지 반복문을 수행
n이 홀수이면 result에 지금까지 거듭제곱한 a를 곱해주고
n이 짝수이면 a에 a를 거듭제곱해주고
n은 2로 나눈 몫으로 변경해준다.
예를 들어 n = 6이면..
result=1
a=a2
n=3
-------------------------
result=a2
a=a4
n=1
-------------------------
result=a6
a=a8
n=0
행렬의 거듭제곱도 마찬가지다.
행렬에서 항등원(result = 1)은 모든 대각원소가 1인 항등행렬
지수가 1 이상이면 반복문을 수행
지수가 홀수이면 result와 a를 곱해주고
지수가 짝수이면 a에 a를 곱해주고
지수를 절반 나눠준다
def matrix_exponentiation(a,b,n,mod):
result = [[0]*n for _ in range(n)]
#항등행렬을 만든다
for i in range(n):
result[i][i] = 1
while b:
if b & 1: #if b % 2 == 1:
result = matrix_multiplication(result,a,n,mod)
a = matrix_multiplication(a,a,n,mod)
b >>= 1 #b //= 2
return exp
근데 이건 다시봐도 왜 되는건지 볼때마다 신기하다...
-----------------------------------------------------------------------------------------------------------------------------
아무튼 이제 구하고자 하는 결과는..?
(A101)으로 초기화하고 X번 거듭제곱한다.
그 결과가
(abcd)라고 해보자.
(aX1)=(abcd)(01)=(bd)
그러므로, aX=b이다. 즉, 거듭제곱한 결과의 0,1 원소가 정답이다.
a,x,m = map(int,input().split())
matrix = [[a,1],[0,1]]
n = 2
print(matrix_exponentiation(matrix,x,n,m)[0][1])
'경쟁 프로그래밍 > Atcoder' 카테고리의 다른 글
ABC 304 복기 - E good graph - union find 활용 (0) | 2023.06.04 |
---|---|
ABC 301 복기.. C - AtCoder Cards (문자열 그리디 알고리즘) (0) | 2023.05.14 |
그래프 연결요소 - union find로 찾아야하는 연결요소 문제 1 - (0) | 2023.03.14 |
ABC 293 복기 - D Tying Rope - 그래프 연결요소, cycle 판단 - (0) | 2023.03.12 |
정수론 - 방정식을 만족하는 순서쌍의 수 세기 - 브루트포스 탐색 범위 줄이는 테크닉 익히기 (0) | 2023.03.11 |