Codeforces 605C Freelancer's Dreams 凸包

Freelancer‘s Dreams

我们把每个二元组看成是平面上的一个点, 那么两个点的线性组合是两点之间的连线, 即x * (a1, b1) + y * (a1, b1) && x + y == 1,

那么n个点的线性组合就是一个凸包, 那么我们求出凸包和(0, 0)到(p, q)直线的交的那个较大值就是最优的组合平均速度。

需要注意的是, 直线和凸包可能没有交点, 需要加入(maxa, 0), (0, maxb)这两个点。

#include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mk make_pair
#define PLL pair<LL, LL>
#define PLI pair<LL, int>
#define PII pair<int, int>
#define SZ(x) ((int)x.size())
#define ull unsigned long long

using namespace std;

const int N = 2e5 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-8;
const double PI = acos(-1);

int dcmp(double x) {
    if(fabs(x) < eps) return 0;
    else return x < 0 ? -1 : 1;
}

struct Point {
    double x, y;
    Point(double x = 0, double y = 0) : x(x), y(y) {}
};

double dist(const Point& a, const Point& b) {
    return sqrt((a.x-b.x) * (a.x-b.x) + (a.y-b.y) * (a.y-b.y));
}

typedef Point Vector;

Point operator + (Vector A, Vector B) {return Point(A.x + B.x, A.y + B.y);}
Point operator - (Vector A, Vector B) {return Point(A.x - B.x, A.y - B.y);}
Point operator * (Vector A, double p) {return Point(A.x * p, A.y * p);}
Point operator / (Vector A, double p) {return Point(A.x / p, A.y / p);}
bool operator < (const Vector &A, const Vector &B) {return A.x < B.x || (A.x == B.x && A.y < B.y);}
bool operator == (const Vector &A, const Point &B) {return dcmp(A.x - B.x) == 0 && dcmp(A.y - B.y) == 0;}
double Dot(Vector A, Vector B) {return A.x * B.x + A.y * B.y;}
double Length(Vector A) {return sqrt(Dot(A, A));}
double Angle(Vector A, Vector B) {return acos(Dot(A, B)/Length(A)/Length(B));}
double Cross(Vector A, Vector B) {return A.x * B.y - A.y * B.x;}
double Area2(Point A, Point B, Point C) {return Cross(B-A, C-A);}

bool IsPointOnSegment(const Point &p, const Point &a1, const Point &a2) {
    if(dcmp(Cross(a1-p,a2-p))) return 0;
    else if(dcmp(p.x-min(a1.x,a2.x)) >= 0 && dcmp(p.x-max(a1.x,a2.x)) <= 0
            && dcmp(p.y-min(a1.y,a2.y)) >= 0 && dcmp(p.y-max(a1.y,a2.y)) <= 0) return 1;
    else return 0;
}

Point GetLineIntersection(Point P, Vector v, Point Q, Vector w) {
    Vector u = P - Q;
    double t = Cross(w, u) / Cross(v, w);
    return P + v * t;
}

int ConvexHull(vector<Point>& p, vector<Point>& ch) {
    int n = p.size(), m = 0;
    sort(p.begin(), p.end());
    for(int i = 0; i < n; i++) {
        while(m > 1 && dcmp(Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2])) <= 0) ch.pop_back(), m--;
        ch.push_back(p[i]); m++;
    }
    int k = m;
    for(int i = n - 2; i >= 0; i--) {
        while(m > k && dcmp(Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2])) <= 0) ch.pop_back(), m--;
        ch.push_back(p[i]); m++;
    }
    return m;
}

int n, p, q;
vector<Point> pt, ch;

int main() {
    scanf("%d%d%d", &n, &p, &q);
    int mxa = -inf, mxb = -inf;
    for(int i = 1; i <= n; i++) {
        int a, b; scanf("%d%d", &a, &b);
        mxa = max(mxa, a);
        mxb = max(mxb, b);
        pt.push_back(Point(a, b));
    }
    pt.push_back(Point(mxa, 0));
    pt.push_back(Point(0, mxb));
    int m = ConvexHull(pt, ch);
    Point v = Point(p, q);
    Point ans = Point(-1, -1);
    for(int i = 0; i < m - 1; i++) {
        if(dcmp(Cross(ch[i], v)) * dcmp(Cross(v, ch[i + 1])) >= 0) {
            if(Cross(v, ch[i + 1] - ch[i]) == 0) continue;
            Point pp = GetLineIntersection(Point(0, 0), v, ch[i], ch[i + 1] - ch[i]);
            if(pp.x > ans.x) ans = pp;
        }
    }
    printf("%.12f\n", v.x / ans.x);
    return 0;
}

/*
*/

Codeforces 605C Freelancer's Dreams 凸包

原文地址:https://www.cnblogs.com/CJLHY/p/10465578.html

时间: 2024-07-30 21:32:41

Codeforces 605C Freelancer's Dreams 凸包的相关文章

[CodeForces-606E] Freelancer&#39;s Dreams 凸包 模型转换

大致题意: 有一个人想要获得p个经验点和q元钱.现在给出n份工作,每份工作每天能得到Ai的经验值和Bi的钱,问最少需要工作多少天, 能使得总经验值>=p,总钱>=q. 先对给出的n份工作以及原点O(0,0),x轴的最大点(maxx,0),y轴最大点(0,maxy)构建凸包,根据凸组合,可知凸包上所有得点以 及凸包边上的点都可以由一天时间得到,那么只要求出射线O~P(p,q)与凸包的交点,即可求出最后的结果. 1 #include<cstdio> 2 #include<iost

Codeforces Round #335 (Div. 1)--C. Freelancer&#39;s Dreams 线性规划对偶问题+三分

题意:p, q,都是整数. sigma(Ai * ki)>= p, sigma(Bi * ki) >= q; ans = sigma(ki).输出ans的最小值 约束条件2个,但是变量k有100000个,所以可以利用对偶性转化为求解 ans = p * y1 + q * y2 约束条件为: Ai * y1 + Bi * y2 <= 1 其中i为0~n-1 也就是n个约束条件. 后面三分搞搞就好了 1 #include <bits/stdc++.h> 2 using names

codeforce 605BE. Freelancer&#39;s Dreams

题意:给你n个工程,做了每个工程相应增长x经验和y钱.问你最少需要多少天到达制定目标.时间可以是浮点数. 思路:杜教思路,用对偶原理很简易.个人建议还是标准解题法,凸包+线性组合. 1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<cstdio> 6 #include<set> 7 #include&

Codeforces 50C Happy Farm 5 凸包

题目链接:点击打开链接 == 难得的y出了一道计算几何.. #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <iostream> using namespace std; #define INF 999999999.9 #define PI acos(-1.0) #define ll long long struct Poi

Codeforces Gym 100492A(凸包,巧妙算法)

题意:给一个凸包,含有N个点,求删除每个点后再求凸包,凸包上的点的平均值.以p/q的最简形式输出,起初q=N.题目要求凸包不允许有两条相邻边平行. 链接:http://codeforces.com/gym/100492 A题 解法:咋一看没啥思路,可能会想到枚举删除每个点,其左边的点到右边的点再求一次凸包 这样的方法,虽然复杂度依然是O(N)的,但是这样编码起来极其困难,而且容易写挂.多想一想,发现只需求若干次凸包即可,正解如下.先求一次凸包,假设凸包上有偶数个点1..n,接下来,每两个点间接着

Codeforces Round #549 (Div. 2) F 数形结合 + 凸包(新坑)

https://codeforces.com/contest/1143/problem/F 题意 有n条形如\(y=x^2+bx+c\)的抛物线,问有多少条抛物线上方没有其他抛物线的交点 题解 \(y=x^2+bx+c=>y+x^2=bx+c\),转换为点\((x,y+x^2)\)在bx+c的直线上 两个点确定一条抛物线,同时也确定了一条直线 需要选择最上面那些点相邻确定的抛物线,所以维护一个上凸包即可 维护上凸包,当前点在前进方向左边需要向后退,cross(a,b)>=0 代码 #inclu

CodeForces 166B (凸包)

求一个多边形是否完全在另一个凸多边形内. 乍一看,好像要判点在多边形内,但复杂度不允许,仔细一想,可以把两个多边形的点混起来求一个共同的凸包,如果共同的凸包依旧是原来凸包上的点,说明是. 1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stdlib.h> 6 #include<vector> 7

Codeforces 1045E. Ancient civilizations 构造 计算几何 凸包

原文链接https://www.cnblogs.com/zhouzhendong/p/CF1045E.html 4K码量构造题,CF血腥残暴! 题解 首先,如果所有点颜色相同,那么直接连个菊花搞定. 然后我们建个凸包. 如果凸包上有大于2段颜色(就是至少四段),比如这样 那么必然无解. 否则就只有一段颜色或者两段颜色: 这里我们先不管这个,考虑一个三角形的构造. 考虑三角形三个顶点颜色不全相同的情况,例如: (两个白点的情况是等价的) 假如三角形区域内没有白点,那么直接全部连到其中一个黑点就好了

Codeforces gym102222 B.Rolling The Polygon 凸包/余弦定理

题意: 有一个不保证凸的多边形,让你滚一圈,计算某点滚出的轨迹多长. 题解: 求出凸包后,以每个点为转轴,转轴到定点的距离为半径,用余弦定理计算圆心角,计算弧长. #include<iostream> #include<cstdio> #include<cmath> #include<cstring> using namespace std; int main() { int t,case1=0; cin>>t; while(t--) { cas