BOJ 13982 Shopping

BOJ 13982 Shopping

문제 링크:

문제 내용

101810^{18} 이하의 양의 정수로 이루어진 길이 nn의 수열 a1,a2,,ana_1, a_2, \cdots, a_n이 있습니다. 다음의 쿼리를 처리하세요.

  • x l r: x % a[l] % a[l+1] % ... % a[r]을 출력합니다. xx101810^{18} 이하의 양의 정수입니다.

입력

첫 줄에 수열의 길이 nn과 쿼리의 개수 qq가 주어집니다. (1n,q200  0001 \le n, q \le 200\;000)

다음 줄에는 수열이 주어집니다.

다음 qq개 줄에는 각각 하나의 쿼리가 주어집니다.

문제 풀이

스포일러

먼저 중요한 관찰을 하나 해야 합니다. xxaia_i가 주어졌을 때, xmodaix \bmod a_ixx 값을 유지하거나 아니면 x2\frac{x}{2} 이하로 감소합니다. 이것의 이유는 다음과 같습니다.

  • x<aix < a_i이면 값이 유지됩니다.
  • aix<2aia_i \le x < 2 a_i이면 값은 xaix - a_i로 바뀌는데, x<2aix < 2 a_ixai<x2x - a_i < \frac{x}{2}는 동치입니다.
  • kaix<(k+1)aik a_i \le x < (k+1) a_i (k2k \ge 2)이면, xmodai<ai<2aixx \bmod a_i < a_i < 2 a_i \le x가 됩니다.

따라서, 각 쿼리에 대해 xx가 감소하는 aia_i들만을 콕콕 집어서 계산해주게 되면 쿼리당 최악 log1018\log 10^{18}번의 나눗셈 연산만을 수행하여 시간 내에 돌 것이라고 예상할 수 있습니다.

이제 [l,r][l, r]에서 xx 이하인 수 중 가장 왼쪽에 있는 수를 빠르게 찾을 수 있으면 이 문제를 해결할 수 있습니다.

한 가지 방법은 sparse table을 쓰는 것입니다.

먼저, 수열의 각 수에 대해 자신보다 작으면서 자신의 오른쪽에 있는 수 중에서 가장 왼쪽에 있는 것의 인덱스를 구합니다. 이 함수를 f(i)f(i)라고 합시다. 이는 스택으로 O(n)\mathcal{O} (n)에 구할 수 있습니다. 이제 f(i)f(i)2k2^k번 중첩한 sparse table을 계산해 둡니다.

이제 쿼리의 (x,l,r)(x, l, r)이 주어졌을 때, 인덱스가 ll 이상이면서 xx 이하인 aia_i를 sparse table을 이용한 이분 탐색으로 구할 수 있습니다. 그러한 인덱스가 없거나 rr보다 오른쪽이면 종료하고, 그렇지 않다면 xxxmodaix \bmod a_i로 바꾼 다음 llf(i)f(i)로 옮겨서 계속 진행합니다.

Last updated on