4570: [Scoi2016]妖怪

4570: [Scoi2016]妖怪

Time Limit: 10 Sec   Memory Limit: 64 MB
Submit: 591   Solved: 152
[ Submit][ Status][ Discuss]

Description

邱老师是妖怪爱好者,他有n只妖怪,每只妖怪有攻击力atk和防御力dnf两种属性。邱老师立志成为妖怪大师,于
是他从真新镇出发,踏上未知的旅途,见识不同的风景。环境对妖怪的战斗力有很大影响,在某种环境中,妖怪可
以降低自己k×a点攻击力,提升k×b点防御力或者,提升自己k×a点攻击力,降低k×b点防御力,a,b属于正实数
,k为任意实数,但是atk和dnf必须始终非负。妖怪在环境(a,b)中的战斗力为妖怪在该种环境中能达到的最大攻击
力和最大防御力之和。strength(a,b)=max(atk(a,b))+max(dnf(a,b))环境由a,b两个参数定义,a,b的含义见前
文描述。比如当前环境a=3,b=2,那么攻击力为6,防御力为2的妖怪,能达到的最大攻击力为9,最大防御力为6。
所以该妖怪在a=3,b=2的环境下战斗力为15。因此,在不同的环境,战斗力最强的妖怪可能发生变化。作为一名优
秀的妖怪训练师,邱老师想发掘每一只妖怪的最大潜力,他想知道在最为不利的情况下,他的n只妖怪能够达到的
最强战斗力值,即存在一组正实数(a,b)使得n只妖怪在该环境下最强战斗力最低。

Input

第一行一个n,表示有n只妖怪。接下来n行,每行两个整数atk和dnf,表示妖怪的攻击力和防御力。
1≤n≤10^6, 0<atk,dnf≤10^8

Output

 输出在最不利情况下最强妖怪的战斗力值,保留4位小数。

Sample Input

3
1 1
1 2
2 2

Sample Output

8.0000

HINT

Source

[ Submit][ Status][ Discuss]


很容易想到二分答案,然后所有妖怪列一个一元二次不等式,看解集的交集是否为空

但这样会TLE。。。。GG

可以把每只妖怪放到二维平面上形成一个点(x,y),过它作一条斜率<0的直线

这样截距和就是某个(a,b)状态下的战斗力了,斜率为-b/a时

对所有点求一个凸包,最大值肯定只出现在凸包右上部分

直接枚举那一块就好了,每个点有个斜率的范围,在这个范围内它都是战力最大的

简单的数学推导可以知道,点(x,y)在斜率为k时的战力为x + y - k*x - y/k >= x + y + 2*sqrt(x*y)

要注意这个斜率能否取到,,如果可以就是这个值,否则是与前后点的斜率其中一个

毕竟这是个长得很像打钩函数的函数,,也可以求导证明

#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<bitset>
using namespace std;

const int maxn = 1E6 + 10;
typedef long long LL;
typedef double DB;
const DB INF = 1E10;
const DB eps = 1E-9;

struct Point{
	int x,y; Point(){}
	Point(int x,int y): x(x),y(y){}
	bool operator < (const Point &B) const 
	{
		if (x < B.x) return 1;
		if (x > B.x) return 0;
		return y < B.y;
	}
	Point operator - (const Point &B)
	{
		return Point(x - B.x,y - B.y);
	}
}p[maxn],s[maxn*2];
typedef Point Vector;

int n,tp;
DB Ans = 1E16;

LL Cross(const Vector &v1,const Vector &v2) {return 1LL*v1.x*v2.y - 1LL*v2.x*v1.y;}
bool Equal(const DB &x,const DB &y) {return fabs(x - y) <= eps;}
bool fcmp(const DB &x,const DB &y) {return x > y || Equal(x,y);}

DB slope(Point p1,Point p2)
{
	Point p = p2 - p1;
	return Equal(p.x,0.000)?INF:(DB)(p.y)/(DB)(p.x);
}

void Work(DB K,Point p)
{
	if (fabs(K) < eps) return;
	DB x = p.x,y = p.y;
	Ans = min(Ans,x + y - K*x - y/K);
}

int getint()
{
	char ch = getchar(); int ret = 0;
	while (ch < '0' || '9' < ch) ch = getchar();
	while ('0' <= ch && ch <= '9')
		ret = ret*10 + ch - '0',ch = getchar();
	return ret;
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
	#else
		freopen("4570.in","r",stdin);
		freopen("4570.out","w",stdout);
	#endif
	
	n = getint();
	for (int i = 1; i <= n; i++)
	{
		int x = getint(),y = getint();
		p[i] = Point(x,y);
	}
	sort(p + 1,p + n + 1);
	for (int i = 1; i <= n; i++)
	{
		while (tp > 1 && Cross(p[i] - s[tp-1],s[tp] - s[tp-1]) > 0) --tp;
		s[++tp] = p[i];
	}
	int k = tp;
	for (int i = n - 1; i; i--)
	{
		while (tp > k && Cross(p[i] - s[tp-1],s[tp] - s[tp-1]) > 0) --tp;
		s[++tp] = p[i];
	}
	--tp; s[0] = s[tp]; s[tp+1] = s[1];
	if (tp == 1) Work(-sqrt((DB)(s[1].y)/(DB)(s[1].x)),s[1]);
	for (int i = k; i <= tp; i++)
	{
		DB B = slope(s[i],s[i-1]),A = slope(s[i+1],s[i]);
		if (fcmp(A,0.000) && fcmp(B,0.000)) continue;
		if (B > A) B = -INF;
		DB K = -sqrt((DB)(s[i].y)/(DB)(s[i].x));
		if (B <= K && K <= A) Work(K,s[i]);
		else Work(A,s[i]),Work(B,s[i]);
		if (fcmp(A,0.000)) break;
	}
	printf("%.4f",Ans);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值