일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 브루트포스
- BFS
- boj
- 이분탐색
- lis
- dfs
- 에라토스테네스의 체
- 플로이드와샬
- 누적합
- 수학
- 세그먼트트리
- 구현
- 펜윅트리
- LazyPropagation
- 그리디
- 다익스트라
- 삼분탐색
- lca
- 투포인터
- 백준
- MST
- 크루스칼
- 좌표압축
- 이분매칭
- 정렬
- DisjointSet
- DP
- 이진탐색
- 비트마스크
- 위상정렬
Archives
- Today
- Total
lastknight00
[백준]통나무 자르기(1114) 본문
문제 링크 : [백준]통나무 자르기(1114)
문제 설명
길이 L의 통나무가 주어지고, 통나무를 자를 수 있는 위치가 K개 주어집니다.
그 위치 중 C번만 나무를 자르는 경우중에서 가장 긴 나무의 길이가 가장 작게 했을 때, 가장 긴 나무의 길이와 가장 처음 자르게 되는 위치를 구하세요.(자를 수 있는 처음 위치가 여러가지인 경우, 제일 먼저 자르는 것을 출력하세요.)
입력
L(통나무의 길이, 1 <= L <= 1,000,000,000)
K(통나무를 자를 수 있는 위치의 갯수, 1 <= K <= 10,000)
C(최대로 자를 수 있는 횟수, 1 <= C <= 10,000)
Pi(통나무를 자를 수 있는 위치(통나무의 제일 왼쪽 기준))
9 2 1
4 5
출력
5 4
카테고리
#이분탐색 #그리디
시간 복잡도 상한
O(K2), O(C2), O(K * c)
해결 방법
- DP로 접근하려고 하였으나, 10,000 * 10,000의 메모리가 필요 할 것 같아 접었습니다.
- 특정 길이 이내로 자를 수 있는지를 파악하는 것은 어렵지 않을 것 같습니다.
2-1. 기준 길이를 정하고, 인덱스를 순차적으로 순회하면서 누적합을 구하며, 기준 길이보다 길어지게 되면 그 위치에서 자르고 다시 누적합을 구하는 식으로 하면 됩니다.
2-2. 자르는 횟수가 C보다 작거나 같으면 기준 길이 이하로 가장 긴 통나무를 만들 수 있습니다. - 그러나 그렇게 되면 특정 길이에서 K번의 시간복잡도가 발생하며, 기준길이 모두를 탐색하게 되면, 10억 * K의 시간복잡도가 생겨서 TLE가 됩니다.
- 그런데 특정 길이에서 성공을 하였다면, 우리는 그것보다 긴 길이를 확인할 필요가 없습니다.
- 이미 특정 길이에서 성공하였는데, 우리는 성공할 수 있는 최소길이를 구하는 것이기 때문에 그것보다 큰 값은 궁금하지 않습니다.
- 반대로, 특정길이에서 실패하였다면, 그 길이보다 작은 길이는 어차피 실패할 것이므로 확인할 필요가 없습니다.
- 즉 특정 길이를 이분탐색으로 하면서 구하면 빠르게 답을 구할 수 있습니다.
- 단, 자르는 위치가 순서대로 주어지는 것이 아니기 때문에 입력 받은 위치를 정렬해야 합니다.
- 그리고 특정 길이보다 긴 나무 토막이 존재한다면 그 길이는 무조건 실패하는 것으로 처리해야 합니다.
- 그렇다면 제일 먼저 자르는 위치는 어떻게 구할까요??
- 2에서 특정길이 이상의 누적합이 발생하였을 때, 자르는 위치를 뒤에서부터 탐색한다면, 자르는 위치는 최대한 앞으로 당겨지면서 구해질 것입니다.
- 따라서 뒤에서 잘라오면서 구하면 마지막으로 자르는 곳이 그 위치가 될 것입니다.
- 단, 자른 횟수가 C보다 작다면 무조건 맨 앞에서 한번 더 자를 수 있으므로, 맨 앞이 답이 됩니다.
시간복잡도
O(KlogL)
코드
#include<cstdio>
#include<algorithm>
#define N 1000000000
int n,m,k,d[10001],e[10001],i,a,b,c,s,l,r=N,x,p;
int main(){
scanf("%d%d%d",&n,&m,&k);
for(i=0;i<m;i++)scanf("%d",d+i);
d[m]=n;
std::sort(d,d+m);
e[0]=d[0];
for(i=1;i<=m;i++)e[i]=d[i]-d[i-1];
while(l<=r){
x=(l+r)/2;
for(p=s=c=0,i=m;i>=0;i--){
if(e[i]>x){
c=k+1;
break;
}
if(s+e[i]>x){
s=0,c++;
p=i;
}
s+=e[i];
}
if(c>k)l=x+1;
else {
a=x;r=x-1;
b=c==k?d[p]:d[0];
}
}
printf("%d %d",a,b);
}
'PS' 카테고리의 다른 글
[백준]36진수(1036) (0) | 2020.07.10 |
---|---|
[백준]연속합 2(13398) (0) | 2020.07.10 |
[백준]한조 대기 중(14433) (0) | 2020.07.05 |
[백준]노트북의 주인을 찾아서(1298) (0) | 2020.07.05 |
[백준]열혈강호4(11378) (0) | 2020.07.05 |
Comments