codeforces 606 E. Freelancer's Dreams(凸包)

传送门: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<<"\n"
#define debug() cout<<"I love Miyamizu Mitsuha forever.\n"
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<<"\n";
    return 0;
}

 

posted @ 2020-05-08 01:29  GGMU  阅读(178)  评论(0编辑  收藏  举报