어떤 땅의 i 의 너비 Wi 와 Hi 가 주어진다.

이 때 가격은 Wi * Hi 이다.


- 한번에 여러개  된다면, (해당 땅 중 Wi의 최댓값 ) * (해당 땅 중 Hi의 최댓값)  으로 가격을 매긴다.


따라서 땅을 최소 비용으로 묶어서 살 경우 최소 비용은 ?


일단 무조건 wi를 기준으로 정렬을 시킨다.

이 때 만약 Wi 와 Hi 가 Wj , Hj보다 더 크다면 무조건 묶는게 이득이다. 

따라서 O(n) 시간으로 탐색하면서 더 큰 애들을 지워나간다.


그렇게 되면 현재 Wi 는 오름차순, Hi 는 내림차순으로 정렬된다.

 

그러고 DP를 생각해보자!


DP[i] = min (DP[j-1] + b[j] * a[i]) 의 식이 성립한다. ( b 는 내림차순)


그러므로 Convex Hull Trick 을 사용하면 된다.


이 때 순차적으로 DP[i] 값을 모두 구해나가야 한다.

따라서 O(n* logn) 의 시간복잡도를 지닌다.



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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
 
using namespace std;
typedef long long ll;
 
struct convex{
    vector<ll> M;//기울기을 의미한다.
    vector<ll> B;//y절편의 값들
    //결국 조심해야될것은 이게 getval이나 bad가 long long 범위를 넘어서는지에 대한 거다
    bool bad(int l1,int l2,int l3){
        return (B[l3]-B[l1]*(M[l1]-M[l2]) < (B[l2]-B[l1])*(M[l1]-M[l3]));
    }
 
    double Cross(int a, int b) {
        return (double)(B[b] - B[a]) / (M[a] - M[b]);
    }
 
    void add(ll m,ll b){
        if(M.size()>0){
            if(M[M.size()-1]== m){
                B[M.size()-1]= min(B[M.size()-1],b);
            }
            else{
                M.push_back(m);
                B.push_back(b);
            }
        }
        else{
            M.push_back(m);
            B.push_back(b);
        }
 
        while(M.size()>=3 && Cross(M.size()-3,M.size()-2)> Cross(M.size()-2,M.size()-1) )
        {
            M.erase(M.end()-2);
            B.erase(B.end()-2);
        }
    }
 
    ll getval(ll x,int id){
        return B[id] + x*M[id];
    }
    ll query(ll x){
        int l = 0,r = M.size()-1,mid;
 
        while(l<r){
            mid = (l+r)/2;
            if(Cross(mid,mid+1)>=x)
                r = mid;
            else
                l = mid+1;
        }
        return getval(x,l);
    }
};
 
 
 
 
ll n;
pair<ll,ll> arr[50500];
 
 
int main(){
 
freopen("input.txt","r",stdin);
 
scanf("%lld",&n);
 
for(int i = 0 ; i < n ; i++){
    scanf("%lld %lld",&arr[i].first,&arr[i].second);
}
 
convex cv;
 
sort(arr,arr+n);
reverse(arr,arr+n);
 
ll now = -1;
ll prev = 0;
 
for(int i =0 ; i < n ; i++){
    if(now >= arr[i].second)    
        continue;
    now = arr[i].second;
    cv.add(arr[i].first,prev);
    prev = cv.query(arr[i].second);
}
 
 
printf("%lld",prev);
 
 
}
cs


'알고리즘' 카테고리의 다른 글

Usaco Gold) Fair Photography  (0) 2018.06.03
[기하] 다각형의 내부 외부 판별  (0) 2018.05.13
BOJ 6171) 땅따먹기  (0) 2018.05.13
DP최적화 - Convex Hull Trick  (0) 2018.05.06
Sqrt Decompositon(평방분할) & Mo's Algorithm  (0) 2018.04.05
문자열 해싱  (0) 2018.03.31

+ Recent posts