문제 정의


무한 수열 A를 푸는 문제 입니다.

 - A[0] = 1;

 - A[i] = A[i/P] + A[i/Q] ( i>=1, i/P 또는 i/Q가 정수가 아닐 때는 가우스 기호를 이용한다. ( 가우스 기호, [3.4] = 3)

 - N, P, Q가 주어질 때, A[N]을 구하여라. ( ,  )




문제 풀이 - 1


이 문제는 전형적인 DP 문제입니다. 

피보나치 문제에서 DP[n] = DP[n-1] + DP[n-2] 의 점화식으로 n번째 값을 구하기 위해 이전에 계산한 n-1, n-2번째 값을 이용합니다.


하지만, 이 문제의 큰 문제는 N과, P,Q의 범위입니다. N의 범위가 커 변수에 모두 저장할 수 없습니다.

첫 번째로 생각한 방법은 STL의 map을 이용해 저장하는 방법입니다. 실제 10^12크기의 변수는 메모리 제한에 걸리니

실제 사용되는 양은 그렇게 많지 않아 map에 저장해 사용하면 가능할 것이라 생각했습니다.




소스코드 - 1


#include < stdio.h >
#include < map >
using namespace std;
typedef unsigned long long ull;
ull N, P, Q;
map < ull, ull > m;
ull dp(ull x) {
	if (x == 0)
		return 1;
	if (m[x] != 0)
		return m[x];
	return m[x] = dp((ull)x / P) + dp((ull)x / Q);
}
int main() {	
	scanf("%lld%lld%lld", &N, &P, &Q);
	printf("%lld\n", dp(N));
	return 0;
}






문제 풀이 - 2


 map을 이용하면 편리하게 문제를 금방풀 수 있었지만, 허무해서 다른 방법은 없을까 생각해봤습니다.

한 가지 떠오른 방법은 N으로부터 P와 Q가 나눠지기 때문에 나눠진 수를 이용하면 저장할 수 있겠다 싶었습니다.

즉, N에서 P를 1번 나눈 값은 N/P이고 P는 1번 나누었고, Q는 0번 나누었습니다. 

N에서 같은 p와 q번 P,Q를 나눈 값은 언제나 동일한 점을 알았고, 이를 이용해 다음처럼 구현할 수 있었습니다.




소스코드 - 2


dp의 크기는 P와 Q의 최소값인 2로 나눌때의 최대값, 즉 10^12 = 2^10^4 으로 약 40 이상으로 잡으면 됩니다.


 
#include < stdio.h >
typedef unsigned long long ull;
ull dp[50][50], N, P, Q;
ull solve(ull x, int p, int q) {
	if (x == 0)
		return 1;
	if (dp[p][q] != 0)
		return dp[p][q];
	return dp[p][q] = solve((ull)x / P, p + 1, q) + solve((ull)x / Q, p, q + 1);
}

int main() {
	scanf("%lld%lld%lld", &N, &P, &Q);
	printf("%lld\n", solve(N, 0, 0));
	return 0;
}

'알고리즘 문제풀이' 카테고리의 다른 글

BOJ 1194 달이 차오른다, 가자.  (0) 2020.08.11
BOJ 6087 레이저통신  (0) 2020.08.09
BOJ 11505 구간 곱 구하기  (0) 2020.08.06
1344 축구  (0) 2018.06.01
1670 정상 회담 2  (0) 2018.05.17

+ Recent posts