일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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
- 구현
- 백준
- 위상정렬
- lis
- 누적합
- 이분매칭
- LazyPropagation
- 비트마스크
- DisjointSet
- 삼분탐색
- 세그먼트트리
- dfs
- 투포인터
- 이분탐색
- 펜윅트리
- boj
- 수학
- DP
- 브루트포스
- MST
- 정렬
- 좌표압축
- 그리디
- 플로이드와샬
- 에라토스테네스의 체
- 이진탐색
- 크루스칼
- 다익스트라
- lca
Archives
- Today
- Total
lastknight00
[백준]블록 쌓기(9998) 본문
문제 링크 : [백준]블록 쌓기(9998)
문제 설명
N칸에 걸쳐 블록을 임의의 높이로 두 줄이 쌓여있습니다.
두 줄의 블록을 가운데를 가장 낮게 하는 V자 형태로 변경하고 싶습니다.
쌓여있는 블록을 빼거나, 추가할 수 있는데, 이 행동을 가장 적게 수행하여 V자로 만드는 횟수를 구하세요.
입력
N(칸의 갯수, 1 <= N <= 300,000)
Yi(첫 줄에 쌓인 각 칸의 블록 갯수, 0 <= Yi <= 212)
Di(두번째 줄에 쌓인 각 칸의 블록 갯수, 0 <= Di <= 212)
3
1 2 3
3 2 2
출력
3
카테고리
#삼분탐색
시간 복잡도 상한
O(NlogM)(M은 블록 높이의 범위)
해결 방법
- f(x)를 중앙의 높이가 x일 때, 이동해야 하는 블록의 수라고 정의하면, f(x)는 U자형 이차함수 그래프를 이룹니다.
- v를 구하고자 하는 최소값을 가질 때의 x라고 하면, x가 v보다 작거나, 크면 그때의 f(x)는 f(v)보다 커집니다.
- 따라서 f(x)의 변곡점을 찾으면 됩니다.
- 미분을 이용해도 되지만, 정확한 함수를 구하기 어렵기 때문에, 삼분탐색을 이용해서 풀 수 있습니다.
- 결정 함수는 각 위치별 이동해야 하는 블록의 갯수들의 합입니다.
- 다만 모든 값의 후보가 정수이기 때문에, 이분탐색을 하면서, f(x)와 f(x+1)의 값이 증가하는지 여부를 보고 답을 구할 수 있습니다.
시간복잡도
O(NlogM)(M은 블록 높이의 범위)
코드
#include<iostream>
#include<algorithm>
#define N 300000
using namespace std;
typedef long long L;
int n,i,c;
L s,l,r=1e12,m,a,b,d[N],e[N];
L x(int p,int o){
return abs(d[c+p]-(m+o))+abs(e[c+p]-(m+o))+(p?abs(d[c-p]-(m+o))+abs(e[c-p]-(m+o)):0);
}
int main(){
ios_base::sync_with_stdio(0);cin.tie(0);
cin>>n;
for(c=n/2;i<n;i++)cin>>d[i];
for(i=0;i<n;i++)cin>>e[i];
while(l<=r){
m=(l+r)/2;
a=x(0,0);b=x(0,1);
for(i=1;c+i<n;i++){
a+=x(i,i);
b+=x(i,i+1);
}
if(a<b)s=a,r=m-1;
else s=b,l=m+1;
}
cout<<s;
}
'PS' 카테고리의 다른 글
[백준]소가 길을 건너간 이유 11(14459) (0) | 2020.09.22 |
---|---|
[백준]우체국(2285) (0) | 2020.09.13 |
[백준]빌보의 생일(4442) (0) | 2020.09.10 |
[백준]중복 제거(13701) (0) | 2020.09.09 |
[백준]헤븐스 키친(14574) (0) | 2020.09.08 |
Comments