[C++ / Algorithm] 백준 28127번 숫자탑과 쿼리 #22
1. 트리
1-1. 문제
의찬이는 숫자가 적힌 블록으로 탑 쌓기를 즐긴다. 어느 날 선우는 의찬이가 쌓는 탑에 규칙이 있음을 알게 되었다! 선우가 알아낸 규칙은 다음과 같다.
- 의찬이가 쌓는 탑은 꼭대기가 1층이고, 1층에는 a개의 블록이 존재한다.
- 1층의 가장 왼쪽 블록에는 1이 적혀있으며, 블록에 적힌 숫자는 오른쪽으로 갈수록 1씩 증가한다.
- i번째 층의 가장 오른쪽 블록보다 i+1번째 층의 가장 왼쪽 블록이 1더 크다.
- i번째 층에 있는 블록의 수보다 i+1번째 층에 있는 블록의 수가 d개 더 많다.
아래 그림은 1에서 4층까지 a=1이고 d=2일 때 의찬이가 쌓은 탑의 모습이다.
각 숫자가 적힌 블록의 위치를 모조리 외운 의찬이는 선우가 던지는 Q개의 질문에 답하고자 한다. 질문은 한 가지 형식이다.
- a d x: a와 d가 주어질 때, x가 적힌 숫자 블록이 몇 번째 층의 몇 번째 숫자인가?
위 그림을 예로 들자. 만약 a=1, d=2, x=12라면 의찬이는 (4,3)이라고 대답한다. 이는 12가 적힌 숫자 블록이 4층에 위치한 3번째 숫자라는 것을 의미한다.
1-2. 입력
첫째 줄에는 선우가 의찬이에게 하는 질문의 개수 Q가 주어진다. (1 <= Q <= 500,000)
이후 Q개의 줄에는 a, d, x가 공백으로 구분되어 주어진다. (1 <= a,d,x <= 1000000)
입력으로 주어지는 모든 값은 정수다.
2. 풀이
n번째 줄의 제일 오른쪽 수보다 n + 1번째 줄의 제일 왼쪽 수가 항상 크므로 1부터 1000000까지의 줄을 이분 탐색한다면 빠르게 문제를 해결할 수 있다.
n번재 줄의 제일 왼쪽 수를 구하는 공식은 다음과 같다. An = (n - 1)(2a + (n - 2)d) / 2 + 1
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
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#include <cmath>
using namespace std;
long long getLeft(long long a, long long d, long long n) {
return (n - 1) * (2 * a + (n - 2) * d) / 2 + 1;
}
int main(void) {
ios_base::sync_with_stdio(0);
cin.tie(0);
int numberOfQueries;
int a, d, value;
cin >> numberOfQueries;
while (numberOfQueries--) {
cin >> a >> d >> value;
long long start = 1;
long long end = 1000000;
long long x, y;
while (start <= end) {
long long middle = (start + end) / 2;
long long left = getLeft(a, d, middle);
if (left <= value) {
start = middle + 1;
x = left;
y = middle;
}
else {
end = middle - 1;
}
}
cout << y << ' ' << value - x + 1 << '\n';
}
}
1
2
3
2
1 2 12
1 2 17
1
2
4 3
5 1
This post is licensed under
CC BY 4.0
by the author.