【Codeforces Round 335 (Div 2)E】【计算几何-凸包 线性规划 三分凸包上最优点】Freelancer's Dreams 二维属性 充最少的钱变得满足要求 [计算几何-凸包模

E. Freelancer's Dreams
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Mikhail the Freelancer dreams of two things: to become a cool programmer and to buy a flat in Moscow. To become a cool programmer, he needs at least p experience points, and a desired flat in Moscow costs q dollars. Mikhail is determined to follow his dreams and registered at a freelance site.

He has suggestions to work on n distinct projects. Mikhail has already evaluated that the participation in the i-th project will increase his experience by ai per day and bring bi dollars per day. As freelance work implies flexible working hours, Mikhail is free to stop working on one project at any time and start working on another project. Doing so, he receives the respective share of experience and money. Mikhail is only trying to become a cool programmer, so he is able to work only on one project at any moment of time.

Find the real value, equal to the minimum number of days Mikhail needs to make his dream come true.

For example, suppose Mikhail is suggested to work on three projects and a1 = 6, b1 = 2, a2 = 1, b2 = 3, a3 = 2, b3 = 6. Also, p = 20and q = 20. In order to achieve his aims Mikhail has to work for 2.5 days on both first and third projects. Indeed,a1·2.5 + a2·0 + a3·2.5 = 6·2.5 + 1·0 + 2·2.5 = 20 and b1·2.5 + b2·0 + b3·2.5 = 2·2.5 + 3·0 + 6·2.5 = 20.

Input

The first line of the input contains three integers n, p and q (1 ≤ n ≤ 100 000, 1 ≤ p, q ≤ 1 000 000) — the number of projects and the required number of experience and money.

Each of the next n lines contains two integers ai and bi (1 ≤ ai, bi ≤ 1 000 000) — the daily increase in experience and daily income for working on the i-th project.

Output

Print a real value — the minimum number of days Mikhail needs to get the required amount of experience and money. Your answer will be considered correct if its absolute or relative error does not exceed 10 - 6.

Namely: let's assume that your answer is a, and the answer of the jury is b. The checker program will consider your answer correct, if .

Sample test(s)
input
3 20 20
6 2
1 3
2 6
output
5.000000000000000
input
4 1 1
2 3
3 2
2 3
3 2
output
0.400000000000000
Note

First sample corresponds to the example in the problem statement.



【Codeforces Round 335 (Div 2)E】【计算几何-凸包 线性规划 三分凸包上最优点】Freelancer's Dreams 二维属性 充最少的钱变得满足要求 [计算几何-凸包模板]

#include<stdio.h>
#include<iomanip>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;}
template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;}
const int N=1e5+10,M=0,Z=1e9+7,ms63=1061109567;
struct point
{
	int x,y;
	point(){}
	point(int x_,int y_){x=x_;y=y_;}
	bool operator < (const point& b)const
	{
		return x!=b.x?x<b.x:y<b.y;
	}
	point operator - (const point& b)const
	{
		return point(x-b.x,y-b.y);
	}
	LL operator * (const point& b)const
	{
		return (LL)x*b.y-(LL)y*b.x;
	}
}a[N];
int s[N];
int n;
double X,Y;
void solve()
{
	scanf("%d",&n);
	scanf("%lf%lf",&X,&Y);
	for(int i=1;i<=n;++i)scanf("%d%d",&a[i].x,&a[i].y);
	sort(a+1,a+n+1);							//按照(先x从小到大,后y从小到大)排序
	int top=0;
	for(int i=1;i<=n;i++)
	{
		while(top&&a[i].y>=a[s[top]].y)--top;	//这是针对这道题目的优化,同时还有着去重点的作用
		while(top>=2&&(a[i]-a[s[top-1]])*(a[s[top]]-a[s[top-1]])<=0)--top;
		s[++top]=i;
	}
	double ans=max(X/a[s[1]].x,Y/a[s[1]].y);
	for(int i=1;i<top;++i)
	{
		point p1=a[s[i]];
		point p2=a[s[i+1]];
		double l=0;
		double r=1;
		double tmpl;
		double tmpr;
		for(int tim=1;tim<=200;++tim)
		{
			double lm=(l+l+r)/3;
			double rm=(l+r+r)/3;
			tmpl=max(	X/(lm*p1.x+(1-lm)*p2.x),	Y/(lm*p1.y+(1-lm)*p2.y)	);
			tmpr=max(	X/(rm*p1.x+(1-rm)*p2.x),	Y/(rm*p1.y+(1-rm)*p2.y)	);
			tmpl<tmpr?r=rm:l=lm;
		}
		gmin(ans,tmpl);
	}
	printf("%.15f\n",ans);
}
int main()
{
	solve();
	return 0;
}
/*
【trick&&吐槽】
这题本来看着是线性规划或是计算几何。我是计算几何渣渣,于是一直不敢做。
直到hack被抢,无所适从,才在最后20分钟开始暴力冲一发。
没想到竟然过了pretest,很激动却最后wa on test 75.天啊噜!

不过,这道题教会了我很多做人的道理!
1,学会了——"通过线段两个端点,比例系数之和1可以构成线段之间任意点"的知识(噗,应该是忘掉的高中知识)。
2,知道了自己写了一年的凸包程序是有问题的
	凸包经常考虑去重点
	凸包可以直接按照(x升序,y升序)排序,然后求一个上凸包和一个下凸包,拼在一起就是答案。
3,对于变量的存储空间,int是4byte,LL是8byte,double也是8byte,long double却只是12byte。
	long double的精度,是没有LL高的,能用LL的地方,就不要用long double
4,这道题的变量都在[1,1e6]之间。于是答案的上限也不过只有1e6.
5,真正的错误是我凸包没判重点=w=!比赛的时候只要判重点就能AC了啊!

【题意】
我们初始属性是(0,0),我们想要变强。
可是!不充钱,怎么变得更强?
于是有n(1e5)个充钱大礼包。
对于每个大礼包,可以用1单位价值的钱,获取(a[i].x,a[i].y)的属性提升。a[i].x和a[i].y都是[1,1e6]范围的数。
钱是虚拟货币,所以单位为double。
问你,要至少冲多少钱,才能使得自己的属性变成至少为(X,Y)。
即最后的二维(x,y),要满足x>=X&&y>=Y。

【类型】
计算几何-凸包

【分析】
这题,对于很多大神而言就是一眼题。
因为有一个特别棒的做法。就是先求凸包(实际是上凸包)——
然后有一个性质,就是,对于一个三角形ABC,我们可以用k*AB+(1-k)*AC来表示出BC上任意一点的坐标。

于是,我们就有——
对于凸包边界上的所有点,我们都可以用大小为1的成本得到。
于是,我们可以舍弃掉原来有的凸包内部的初始点(因为这些初始点,同样成本为1,得到的价值没有凸包上的点优)。
而凸包外部的点,是我们用1成本达不到的,自然不需要考虑。

于是,这道题,我们求得凸包之后,直接引出一个(X,Y)的向量(更准确地讲,叫做射线),
这个射线与上凸包的交点(设为(x_,y_)),距离圆心的距离设为d,
而(X,Y)这个点,距离圆心的距离设为D,
那么答案就是D/d.

于是,我们可以枚举上凸包的所有边,判定线段交点。
也可以枚举上凸包的所有边,三分答案——
因为凸包上只有一点,对应于(x_,y_)方向上,权值最小,其它点的权值都是要更大的(权值定义为(max(X/x,Y/y)))
于是,就可以AC这道题啦。

================================================================================

然而,我并不知道这个。我只是猜到答案与凸包有关,可能在凸包相邻点对之间。
于是我用了另外一种做法,是一种没有想过正确性的破釜沉舟的"试一试看,反正不花钱噗"的做法。
我的做法是——虚拟一个(0,0)点,求得凸包。
第一种情况,先用凸包上的所有点,用max(X/a[i].x,Y/a[i].y)更新一遍答案
第二种情况,然后认定答案是我们通过 凸包上的相邻点对 的搭配得到,
设是由p1和p2的搭配得到的,即(X,Y)=kp1+wp2
于是我们三分第一个点所选取的分量,即k,
然后算出第二个点,还需要选取的分量,即w。
用第一个点选取量+第二个点选取量的和,即k+w,来决定三分位置的移动。更新答案最后输出。
要不是我凸包求错了,也是可以AC的啦~~


【时间复杂度&&优化】
我的做法——O(求凸包复杂度+凸包点数*三分次数)
三分凸包上线段的做法——O(求凸包复杂度+凸包点数*三分次数)
求射线与凸包交点做法——O(求凸包复杂度)

*/


【Codeforces Round 335 (Div 2)E】【凸包 线性规划 原始版本】Freelancer's Dreams 二维属性 充最少的钱变得满足要求

#include<stdio.h>
#include<iomanip>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;}
template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;}
const int N=1e5+10,M=0,Z=1e9+7,ms63=1061109567;
struct point
{
	int x,y;
	point(){}
	point(int x_,int y_){x=x_;y=y_;}
	bool operator < (const point& b)const
	{
		return x!=b.x?x<b.x:y<b.y;
	}
	point operator - (const point& b)const
	{
		return point(x-b.x,y-b.y);
	}
	LL operator * (const point& b)const
	{
		return (LL)x*b.y-(LL)y*b.x;
	}
}a[N];
int s[N];
int n;
double X,Y;

int i;
double cnt(double m)
{
	double x=m*a[s[i]].x;
	double y=m*a[s[i]].y;
	if(x>=X&&y>=Y)return m;
	else
	{
		if(x>=X) return m+(Y-y)/a[s[i+1]].y;
		else if(y>=Y)return m+(X-x)/a[s[i+1]].x;
		else return m+max((Y-y)/a[s[i+1]].y,(X-x)/a[s[i+1]].x);
	}
}

void solve()
{
	scanf("%d",&n);
	scanf("%lf%lf",&X,&Y);
	for(int i=1;i<=n;++i)scanf("%d%d",&a[i].x,&a[i].y);
	sort(a+1,a+n+1);							//按照(先x从小到大,后y从小到大)排序
	int top=0;
	for(int i=1;i<=n;i++)
	{
		while(top&&a[i].y>=a[s[top]].y)--top;	//这是针对这道题目的优化,同时还有着去重点的作用
		while(top>=2&&(a[i]-a[s[top-1]])*(a[s[top]]-a[s[top-1]])<=0)--top;
		s[++top]=i;
	}
	double ans=max(X/a[s[1]].x,Y/a[s[1]].y);
	for(i=1;i<top;++i)
	{
		point p1=a[s[i]];
		point p2=a[s[i+1]];
		double l=0;
		double r=1e6;
		double tmpl;
		double tmpr;
		for(int tim=1;tim<=200;++tim)
		{
			double lm=(l+l+r)/3;
			double rm=(l+r+r)/3;
			tmpl=cnt(lm);
			tmpr=cnt(rm);
			tmpl<tmpr?r=rm:l=lm;
		}
		gmin(ans,tmpl);
	}
	printf("%.15f\n",ans);
}
int main()
{
	solve();
	return 0;
}

/*
【trick&&吐槽】
这题本来看着是线性规划或是计算几何。我是计算几何渣渣,于是一直不敢做。
直到hack被抢,无所适从,才在最后20分钟开始暴力冲一发。
没想到竟然过了pretest,很激动却最后wa on test 75.天啊噜!

不过,这道题教会了我很多做人的道理!
1,学会了——"通过线段两个端点,比例系数之和1可以构成线段之间任意点"的知识(噗,应该是忘掉的高中知识)。
2,知道了自己写了一年的凸包程序是有问题的
	凸包经常考虑去重点
	凸包可以直接按照(x升序,y升序)排序,然后求一个上凸包和一个下凸包,拼在一起就是答案。
3,对于变量的存储空间,int是4byte,LL是8byte,double也是8byte,long double却只是12byte。
	long double的精度,是没有LL高的,能用LL的地方,就不要用long double
4,这道题的变量都在[1,1e6]之间。于是答案的上限也不过只有1e6.
5,真正的错误是我凸包没判重点=w=!比赛的时候只要判重点就能AC了啊!

【题意】
我们初始属性是(0,0),我们想要变强。
可是!不充钱,怎么变得更强?
于是有n(1e5)个充钱大礼包。
对于每个大礼包,可以用1单位价值的钱,获取(a[i].x,a[i].y)的属性提升。a[i].x和a[i].y都是[1,1e6]范围的数。
钱是虚拟货币,所以单位为double。
问你,要至少冲多少钱,才能使得自己的属性变成至少为(X,Y)。
即最后的二维(x,y),要满足x>=X&&y>=Y。

【类型】
计算几何-凸包

【分析】
这题,对于很多大神而言就是一眼题。
因为有一个特别棒的做法。就是先求凸包(实际是上凸包)——
然后有一个性质,就是,对于一个三角形ABC,我们可以用k*AB+(1-k)*AC来表示出BC上任意一点的坐标。

于是,我们就有——
对于凸包边界上的所有点,我们都可以用大小为1的成本得到。
于是,我们可以舍弃掉原来有的凸包内部的初始点(因为这些初始点,同样成本为1,得到的价值没有凸包上的点优)。
而凸包外部的点,是我们用1成本达不到的,自然不需要考虑。

于是,这道题,我们求得凸包之后,直接引出一个(X,Y)的向量(更准确地讲,叫做射线),
这个射线与上凸包的交点(设为(x_,y_)),距离圆心的距离设为d,
而(X,Y)这个点,距离圆心的距离设为D,
那么答案就是D/d.

于是,我们可以枚举上凸包的所有边,判定线段交点。
也可以枚举上凸包的所有边,三分答案——
因为凸包上只有一点,对应于(x_,y_)方向上,权值最小,其它点的权值都是要更大的(权值定义为(max(X/x,Y/y)))
于是,就可以AC这道题啦。

================================================================================

然而,我并不知道这个。我只是猜到答案与凸包有关,可能在凸包相邻点对之间。
于是我用了另外一种做法,是一种没有想过正确性的破釜沉舟的"试一试看,反正不花钱噗"的做法。
我的做法是——虚拟一个(0,0)点,求得凸包。
第一种情况,先用凸包上的所有点,用max(X/a[i].x,Y/a[i].y)更新一遍答案
第二种情况,然后认定答案是我们通过 凸包上的相邻点对 的搭配得到,
设是由p1和p2的搭配得到的,即(X,Y)=kp1+wp2
于是我们三分第一个点所选取的分量,即k,
然后算出第二个点,还需要选取的分量,即w。
用第一个点选取量+第二个点选取量的和,即k+w,来决定三分位置的移动。更新答案最后输出。
要不是我凸包求错了,也是可以AC的啦~~


【时间复杂度&&优化】
我的做法——O(求凸包复杂度+凸包点数*三分次数)
三分凸包上线段的做法——O(求凸包复杂度+凸包点数*三分次数)
求射线与凸包交点做法——O(求凸包复杂度)

*/


你可能感兴趣的:(codeforces,贪心,线性规划,题库-CF,计算几何-凸包)