懒人的福利?教你用set维护斜率优化凸包

t=max(a[i]*(f[j])+b[i]*(f[j]/rate[j]))。

t=a*x+b*y，两边同时除以b，得到:

t/b=(a/b)x+y

y=(t/b)-(a/b)*x

 1 int cmp; // 0 compare x , 1 compare slope .
2 struct Point {
3     double x,y,slop;
4     friend bool operator < (const Point &a,const Point &b) {
5         if( !cmp ) return a.x != b.x ? a.x < b.x : a.y < b.y;
6         return a.slop > b.slop;
7     }
8     friend Point operator - (const Point &a,const Point &b) {
9         return (Point){a.x-b.x,a.y-b.y};
10     }
11     friend double operator * (const Point &a,const Point &b) {
12         return a.x * b.y - b.x * a.y;
13     }
14     inline double calc(double a,double b) const {
15         return a * x + b * y;
16     }
17 };
18 set<Point> st;

 1 inline void Pop_right(set<Point>::iterator nxt,const Point &p) {
2     set<Point>::iterator lst;
3     while(1) {
4         lst = nxt , ++nxt;
5         if( nxt == st.end() ) return;
6         if( (*lst-p) * (*nxt-*lst) <= 0 ) return;
7         st.erase(lst);
8     }
9 }
10 inline void Pop_left(set<Point>::iterator prv,const Point &p) {
11     set<Point>::iterator lst;
12     while(prv!=st.begin()) {
13         lst = prv , --prv;
14         if( (*lst-*prv) * (p-*lst) <= 0 ) break;
15         st.erase(lst);
16     }
17 }
18 inline void insert(const Point &p) {
19     cmp = 0;
20     set<Point>::iterator prv,nxt,lst=st.lower_bound(p);
21     if(lst!=st.begin()) Pop_left(--lst,p);
22     lst=st.lower_bound(p);
23     if(lst!=st.end()) Pop_right(lst,p);
24     st.insert(p) , lst = st.find(p);
25     if(lst!=st.begin()) {
26         prv = lst , --prv;
27         Point x = *prv;
28         x.slop = ( p.y - x.y ) / ( p.x - x.x );
29         st.erase(prv) , st.insert(x);
30     }
31     nxt = lst , ++nxt;
32     if(nxt!=st.end()) {
33         Point x = p , n = *nxt;
34         x.slop = ( n.y - x.y ) / ( n.x - x.x );
35         st.erase(lst) , st.insert(x);
36     } else {
37         Point x = p;
38         x.slop = -1e18;
39         st.erase(lst) , st.insert(x);
40     }
41 }

 1 inline double query(const int id) {
2     cmp = 1;
3     const double k = -a[id] / b[id];
4     set<Point>::iterator it = st.lower_bound((Point){0,0,k}); // it can't be st.end() if st isn't empty .
5     if( it==st.end() ) return 0;
6     double ret = it->calc(a[id],b[id]);
7     if( it != st.begin() ) {
8         --it;
9         ret = max( ret , it->calc(a[id],b[id]) );
10     }
11     return ret;
12 }

Bzoj1492:

 1 #include<cstdio>
2 #include<algorithm>
3 #include<set>
4 #include<cmath>
5 using namespace std;
6 const int maxn=1e5+1e2;
7
8 int cmp; // 0 compare x , 1 compare slope .
9 struct Point {
10     double x,y,slop;
11     friend bool operator < (const Point &a,const Point &b) {
12         if( !cmp ) return a.x != b.x ? a.x < b.x : a.y < b.y;
13         return a.slop > b.slop;
14     }
15     friend Point operator - (const Point &a,const Point &b) {
16         return (Point){a.x-b.x,a.y-b.y};
17     }
18     friend double operator * (const Point &a,const Point &b) {
19         return a.x * b.y - b.x * a.y;
20     }
21     inline double calc(double a,double b) const {
22         return a * x + b * y;
23     }
24 };
25 set<Point> st;
26 double a[maxn],b[maxn],rate[maxn],f[maxn],ans;
27
28 inline void Pop_right(set<Point>::iterator nxt,const Point &p) {
29     set<Point>::iterator lst;
30     while(1) {
31         lst = nxt , ++nxt;
32         if( nxt == st.end() ) return;
33         if( (*lst-p) * (*nxt-*lst) <= 0 ) return;
34         st.erase(lst);
35     }
36 }
37 inline void Pop_left(set<Point>::iterator prv,const Point &p) {
38     set<Point>::iterator lst;
39     while(prv!=st.begin()) {
40         lst = prv , --prv;
41         if( (*lst-*prv) * (p-*lst) <= 0 ) break;
42         st.erase(lst);
43     }
44 }
45 inline void insert(const Point &p) {
46     cmp = 0;
47     set<Point>::iterator prv,nxt,lst=st.lower_bound(p);
48     if(lst!=st.begin()) Pop_left(--lst,p);
49     lst=st.lower_bound(p);
50     if(lst!=st.end()) Pop_right(lst,p);
51     st.insert(p) , lst = st.find(p);
52     if(lst!=st.begin()) {
53         prv = lst , --prv;
54         Point x = *prv;
55         x.slop = ( p.y - x.y ) / ( p.x - x.x );
56         st.erase(prv) , st.insert(x);
57     }
58     nxt = lst , ++nxt;
59     if(nxt!=st.end()) {
60         Point x = p , n = *nxt;
61         x.slop = ( n.y - x.y ) / ( n.x - x.x );
62         st.erase(lst) , st.insert(x);
63     } else {
64         Point x = p;
65         x.slop = -1e18;
66         st.erase(lst) , st.insert(x);
67     }
68 }
69 inline double query(const int id) {
70     cmp = 1;
71     const double k = -a[id] / b[id];
72     set<Point>::iterator it = st.lower_bound((Point){0,0,k}); // it can't be st.end() if st isn't empty .
73     if( it==st.end() ) return 0;
74     double ret = it->calc(a[id],b[id]);
75     if( it != st.begin() ) {
76         --it;
77         ret = max( ret , it->calc(a[id],b[id]) );
78     }
79     return ret;
80 }
81
82 int main() {
83     static int n;
84     scanf("%d%lf",&n,&ans);
85     for(int i=1;i<=n;i++) scanf("%lf%lf%lf",a+i,b+i,rate+i);
86     for(int i=1;i<=n;i++) {
87         ans = max( ans , query(i) );
88         f[i] = ans * rate[i] / ( a[i] * rate[i] + b[i] );
89         insert((Point){f[i],f[i]/rate[i],0});
90     }
91     printf("%0.3lf\n",ans);
92     return 0;
93 }
View Code

(来自某中二病晚期患者(不))

posted @ 2018-03-02 11:55  Cmd2001  阅读(1445)  评论(3编辑  收藏  举报