传送门:http://codeforces.com/contest/606/problem/E
解题思路:
我们可以将所有的$(a_{i},b_{i})$视为二维坐标轴上的点$(x,y)$,对于任意两点$(x_{1},y_{1}),(x_{2},y_{2})$,将这两点连起来,所形成的的线段上任意一点为一天的可以获得的量。
那么当选取多个点时该如何考虑呢?假设有三个点A,B,C被选到,设D为BC上任意一点,ABC三点可以选取的点必然为AD上一点,不拿看出,这个范围是三角形ABC内部(含边界)。推广到n个点,单日可获得的必然是这n个点所构成的凸包。
因此任务转化为了凸包内找一个点(x,y),使得$max(p/x,q/y)$最小。假设凸包和$(0,0)$到$(p,q)$的直线有交点,必然是取凸包和直线的交点,求出凸包,然后每一条线都check一下就好了,当然其实最多也只有两条线会相交。若无交点,而必然是凸包的顶点了,枚举一下即可。
从得出的结论可以看出最多不会取超过两个点,因为必然是某一点,或者某两点连成的直线上的点,队友好像是根据这个性质用的三分做的。
比赛的时候发现自己凸包的板子写的天花乱坠,既没有类封装,也没有函数封装,打了半天没打出来。
最后贴上AC代码。
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; typedef pair <double,double> pii; #define rep(i,x,y) for(int i=x;i<y;i++) #define rept(i,x,y) for(int i=x;i<=y;i++) #define per(i,x,y) for(int i=x;i>=y;i--) #define all(x) x.begin(),x.end() #define pb push_back #define fi first #define se second #define mes(a,b) memset(a,b,sizeof a) #define mp make_pair #define dd(x) cout<<#x<<"="<<x<<" " #define de(x) cout<<#x<<"="<<x<<" " #define debug() cout<<"I love Miyamizu Mitsuha forever. " const int inf=0x3f3f3f3f; const int maxn=1e5+5; pii p[maxn]; pii point[maxn];//存放点 double dis(const pii &s1,const pii &s2)//两点间距离 { return sqrt((s1.fi-s2.fi)*(s1.fi-s2.fi)+(s1.se-s2.se)*(s1.se-s2.se)); } pii operator -(const pii &s1,const pii &s2) { return mp(s1.fi-s2.fi,s1.se-s2.se); } double chaji(const pii &s1,const pii &s2)//差积 { return s1.fi*s2.se-s1.se*s2.fi; } bool comp(const pii &s1,const pii &s2) { double x=chaji(s1-point[0],s2-point[0]); if( x>0|| (x==0&&fabs(s1.fi-point[0].fi)<fabs(s2.fi-point[0].fi)) ) return 1; else return 0; } int graham(pii point[],int n)//计算凸包 { int p=0,cnt=0; rep(i,1,n) if( point[i].se<point[p].se||(point[i].se==point[p].se&&point[i].fi<point[p].fi) ) p=i; swap(point[0],point[p]); sort(point+1,point+n,comp); cnt=2; rep(i,2,n) { while(cnt>=2&&chaji( point[cnt-1]-point[i],point[cnt-2]-point[i] )>=0 ) cnt--; point[cnt++]=point[i]; } return cnt; } double a,b; pii node(pii s1,pii s2) { double x=( (s1.se*s2.fi-s1.fi*s2.se)/(s2.fi-s1.fi) )/(b/a-(s2.se-s1.se)/(s2.fi-s1.fi)); double y=b/a*x; return mp(x,y); } int main() { ios::sync_with_stdio(false); cin.tie(0); int n; cin>>n>>a>>b; rep(i,0,n) cin>>p[i].fi>>p[i].se; if(n==1) { cout<<fixed<<setprecision(10)<<max(a/p[0].fi,b/p[0].se); return 0; } int cnt=graham(p,n); double ans=1e18; rep(i,0,cnt-1) { pii point=node(p[i],p[i+1]);//求交点 if(point.fi<=p[i].fi&&point.fi>=p[i+1].fi) ans=min(ans,a/point.fi);//判断交点是否在线段上 } rep(i,0,cnt) ans=min(ans,max(a/p[i].fi,b/p[i].se)); cout<<fixed<<setprecision(10)<<ans<<" "; return 0; }