f(x)를 0에서 시작하여 x를 만드는 최소 비용이라고 하자. X가 작다면 다음 점화식을 왼쪽부터 계산할 수 있다.
f(x)=min(1≤i≤min(K,x)min(f(x−i)+Ai), [x가 짝수](f(x/2)+B)).
하지만 X가 매우 크므로 필요한 값의 범위를 줄여야 한다.
1. 마지막 두 배 연산 뒤의 덧셈
최적 연산열이 두 배 연산을 한 번 이상 사용한다고 하자. 마지막 두 배 연산 이후에 같은 종류의 연산 p+=i가 두 번 등장할 수 없다.
실제로 마지막 두 배 연산 직전의 값이 y이고, 그 뒤에 +i가 두 번 등장한다면, 두 번의 +i를 지우고 마지막 두 배 연산 직전에 +i를 한 번 수행할 수 있다.
2(y+i)=2y+2i
결과는 같지만 비용은 2Ai에서 Ai로 감소하므로 기존 연산열은 최적일 수 없다.
따라서 마지막 두 배 연산 이후에 더해지는 값의 합은
S=1+2+⋯+K=2K(K+1)
이하이다.
2. 덧셈 연산만 사용하는 비용
C(x)를 덧셈 연산만 사용하여 x를 만드는 최소 비용이라고 하자. 작은 x에 대해서는 완전 배낭 점화식으로 계산할 수 있다.
Aq/q가 최소가 되는 q를 하나 고른다. 나머지를 q로 본 그래프를 생각하고, +i에
qAi−iAq
의 가중치를 준다. q의 선택에 의해 모든 가중치는 음이 아니다. 같은 나머지를 두 번 방문하는 부분은 제거한 뒤 그 양만큼 +q로 채울 수 있으므로, 각 나머지에 대한 최적 경로는 q−1개 이하의 간선만 사용하도록 고를 수 있다. 이 경로가 더하는 값은 최대 K(q−1)이다.
따라서 0≤t≤K(q−1)에 대한 C(t)만 계산하면, 충분히 큰 x에 대해 r=xmodq라 할 때
C(x)=qx−rAq+0≤t≤K(q−1)tmodq=rmin(C(t)−qt−rAq)
로 C(x)를 O(1)에 구할 수 있다. 계산 중 매우 큰 덧셈 전용 비용은 충분히 큰 값으로 잘라 두어도 된다.
3. 필요한 구간만 재귀적으로 계산하기
구간 [L,R]의 모든 f(x)가 필요하다고 하자. x∈[L,R]의 최적 연산열이 두 배 연산을 사용한다면, 마지막 두 배 연산 직후의 값은 x−S 이상이다. 따라서 마지막 두 배 연산 직전의 값으로 필요한 범위는
[⌈2max(0,L−S)⌉,⌊2R⌋]
뿐이다.
이 절반 크기의 구간을 재귀적으로 계산한다. 그 뒤 J=[max(0,L−S),R]의 각 위치를 다음 값으로 초기화한다.
- 덧셈만 사용하는 경우의 비용 C(x).
- x가 짝수라면, f(x/2)+B.
이후 J를 왼쪽부터 보면서 모든 1≤i≤K에 대해 x에서 x+i로 비용 Ai의 전이를 한다. 모든 전이는 값이 증가하는 방향이므로 한 번의 순회로 최단 거리를 계산할 수 있다. 마지막에 [L,R]에 해당하는 부분만 반환한다.
처음에는 구간 [X,X]만 요청한다. 재귀 단계에서 구간의 길이를 W라 하면 다음 단계의 길이는 대략 (W+S)/2이므로 항상 O(S)이고, 재귀 깊이는 O(logX)이다. 각 단계에서 길이 O(S)인 구간에 대해 K개의 덧셈 전이를 확인하므로 전체 시간 복잡도는
O(KSlogX)=O(K3logX)
이고, 메모리 복잡도는 O(S+K2)이다.
Solution written by GPT5.6