티스토리 뷰
문제
알고리즘
이분탐색
풀이
갚을 금액, 기한, 하루에 최소 갚을 금액이 주어졌을 때, 조건을 충족하는 $X$를 구하는 문제입니다.
문제를 풀기 위한 첫 번째 단계는 $X$를 결정해야하는 것입니다. 결정문제는 이분탐색으로 바꿀 수 있습니다. 이 문제가 어려운 이유는 $X$를 결정했을 때, 그대로 시뮬레이션하여 $K$일 이내에 돈을 갚을 수 있는지 계산하게 되면 시간초과가 발생하기 때문입니다.
이유는 $N$제한이 $10^{12}$이기 때문입니다. $X$를 결정하는 시간복잡도는 $O(logN)$에 해당하는데 그대로 시뮬레이션 하게 되면 $X$마다 선형시간이 요구되기 때문입니다.
한가지 할 수 있는 관찰 중 하나는 John이 갚아나가는 금액은 비오름차순의 형태를 띤다는 것입니다. 이를 이용해 하루에 갚아나가야 하는 금액이 $A$라면 남은 돈에서 $A, A, A$... 처럼 하나씩 빼지말고 계산을 통해 $A$를 몇개 빼야할지 계산하면 됩니다.
이를 계산하기 위해선 하루에 갚아야 하는 금액 $A$에서 $X$를 곱하면 $A$를 내야하는 경계선 금액(남은 돈)이 나오게 됩니다. 이 값을 $leftMost$라는 변수를 통해 나타냈습니다. 위 문단에서 '몇개'를 계산하는 것은 (rest - leftMost + givePerday) / givePerday; 통해 가능합니다. givePerday를 더하는 이유는 올림을 계산하기 위함입니다. 마지막으로 최적화를 위해 $solve()$함수 내에서 $day$가 $K$를 넘거나 남은 금액이 0 이하가 되면 while문을 종료하도록 했습니다.
코드
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < n; ++i)
#define REP(i, n) for (int i = 1; i <= n; ++i)
using namespace std;
#define int long long
int N, K, M;
bool solve(int m) {
int rest = N;
int day = 0;
while (1) {
int givePerday = rest / m;
if (givePerday <= M) {
int ret = day + (rest + M-1) / M;
return ret<=K;
}
int leftMost = givePerday * m;
int dayCnt = (rest - leftMost + givePerday) / givePerday;
day += dayCnt;
if (day > K) return false;
int give = dayCnt * givePerday;
rest -= give;
if (rest <= 0) {
break;
}
}
return day <= K;
}
signed main() {
cin.tie(NULL);
cout.tie(NULL);
ios::sync_with_stdio(false);
cin >> N >> K >> M;
int lo = 1;
int hi = N;
int best = -1;
while (lo <= hi) {
int mid = (lo + hi) / 2;
if (solve(mid)) {
best = mid;
lo = mid + 1;
} else {
hi = mid - 1;
}
}
cout << best;
return 0;
}
'Algorithm' 카테고리의 다른 글
[백준 3015] 오아시스 재결합 (0) | 2021.05.05 |
---|---|
[백준 20971] No Time to Paint (0) | 2021.04.30 |
[백준 9376] 탈옥 (0) | 2021.04.25 |
[백준 2398] 3인 통화 (0) | 2021.04.24 |
[백준 4716] 풍선 (0) | 2021.04.15 |
- Total
- Today
- Yesterday
- spring
- SCC
- DP
- implementation
- Suffix Array
- kmp
- 좌표압축
- sweeping
- 2-SAT
- Fenwick
- 펜윅트리
- union find
- bfs
- 정렬
- Oracle
- 동적계획법
- knapsack
- greedy
- string
- sorting
- dfs
- hld
- 스위핑
- 이분매칭
- 이분탐색
- dijkstra
- 세그먼트트리
- spring boot
- 트라이
- Segment tree
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |