「凸包」
凸包
Upd10.17
来补坑啦!
总结一下,我做过的凸包题,好像只有两道。
上一道现在还没有A(呜呜
基本的凸包就是一个套路,就是你先化简一个看上去很丑的柿子,然后把它化简成$y=ax+b$的形式
基本上就是有很多个a与b,那么一般就是求所有直线在同一个x条件下的最大值/最小值。
那么就成为了静态凸包的基本问题了:静态维护上凸包/下凸包。
具体的,以下凸包为例。(就做过下凸包,上凸包应该差不多唔
要维护下凸包,实际上就是找在每个x条件下最靠下边的那一条线。
我们把所有的直线按照斜率降序排序,为什么呢
因为我们知道当x趋近正无穷时一定是斜率小的y值小,我们想让这个凸包更加有棱有角
所以要先把一些不够优秀的直线放到凸包里,希冀它能作出一点贡献
那么重点来了,如何维护下凸包?
假如我们现在有一个新加入的直线,我们假设它与栈顶直线的交点横坐标为x1,与栈顶-1直线的交点横坐标为x2.
考虑到加入的直线的斜率一定是单减的,那么画一下图可以发现(其实是我语文不好)当x1<x2时,栈顶的直线一定不能够构成下凸包
那么此时就可以把栈顶pop掉了,这样一直做,一直到构成下凸包为止。
正确性?画画图显然啊(再次黑框)
例题 [CF535E]Tavas and Pashmaks
设$y_{i}=\frac{S_{1}}{a_{i}}+\frac{S_{2}}{b_{i}}$
那么我们实际上就是要求一对S1,S2使得$y_{i}$最小。
考虑此时有两个未知数,不好搞,总不能搞三维凸包吧。
考虑到S1S2的数据范围是一切实数,那么考虑到将S1S2同时缩小倍数关系选手的y关系不变。
那么就把S2缩成1好咯。
柿子变成了$y_{i}=\frac{A}{a_{i}}+\frac{1}{b_{i}}$
那就好搞咯,静态维护下凸包就好咯。
入门题。(但是我考试时候屁都不会)
代码
1 #include<bits/stdc++.h> 2 #define lb long double 3 #define N 600005 4 using namespace std; 5 const lb eps=9e-25; 6 inline int read(){ 7 register int x=0,f=1;char ch=getchar(); 8 while(!isdigit(ch)) f=ch=='-'?-1:1,ch=getchar(); 9 while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-48,ch=getchar(); 10 return x*f; 11 } 12 struct node{int a,b,id;}q[N],p[N]; 13 bool operator < (const node &a,const node &b){return a.a!=b.a?a.a<b.a:a.b<b.b;} 14 int sta[N],top,n; 15 int v[N]; 16 map<int,int>M; 17 #define A(x) q[x].a 18 #define B(x) q[x].b 19 #define ID(x) q[x].id 20 long double point(int x,int y){return 1.0L*(B(x)-B(y))*A(x)*A(y)/B(x)/B(y)/(A(y)-A(x));} 21 int main(){ 22 // freopen("text.in","r",stdin); 23 n=read(); 24 for(int i=1;i<=n;++i) A(i)=read(),B(i)=read(),ID(i)=i; 25 26 sort(q+1,q+n+1);int io=0; 27 for(int i=1;i<=n;++i) 28 if(A(i)==A(i-1)&&B(i)==B(i-1)&&i!=1) M[ID(i)]=M[ID(i-1)]; 29 else M[ID(i)]=ID(i),p[++io]=q[i]; 30 for(int i=1;i<=io;++i) q[i]=p[i]; 31 for(int i=1;i<=io;++i){ED:bool D=0; 32 while(top&&A(sta[top])==A(i)) top--,D=1; 33 while(top>=2&&point(sta[top],i)<point(sta[top-1],i)) top--,D=1; 34 while(top&&point(sta[top],i)<eps) top--,D=1; 35 if(D) goto ED; 36 sta[++top]=i; 37 } 38 for(int i=1;i<=top;++i) v[M[ID(sta[i])]]=1; 39 for(int i=1;i<=n;++i) if(v[M[i]]) printf("%d ",i); 40 return 0; 41 }
UPD10.25模拟测试
T1明明是一道傻雕二分答案被我生生肛成了凸包....然后还A了...
UPD10.26模拟测试
T1是个凸包我本着“两天T1不可能考同一个考点"就打了个二分...