【bzoj4570 scoi2016】妖怪

 

题目描述

邱老师是妖怪爱好者,他有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只妖怪在该环境下最强战斗力最低。

输入输出格式

输入格式:

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

输出格式:

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

题意:
n只妖怪,有atk和dnf属性,每次可以选择一个环境a,b:可以使atk下降a*k,dnf上升b*k,或者相反,定义潜力为环境中最大atk和dnf的和,选择环境最小化最大的潜力;

题解:
①首先和a,b具体的值是无关的,只与a,b的比值有关:简化关系对于却定的a/b最大的潜力值是mx = A+B+A*b/a + B*a/b (令atk=A,dnf=B),      
令 k = -b/a,mx = A+B-(A*(1/k) + B*(k));后半部分对勾函数在k=sqrt(A/B)取得最小值;

联想对于一个定点(x,y)斜率为k,那么其在x,y轴上的截距为:

x + y – x*k – y*(1/k),所以令x为B,y为A,就变成了截距的最大值最小。那么确定的k对n个点截距最大的一定在上凸包的右半部分上。

枚举凸包上的点,如果k=sqrt(A/B)可选,则选,否则选择凸包的边界为k。

算很隐蔽了吧。

 

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<algorithm>
 5 #define ll long long
 6 using namespace std;
 7 const int N = 1000010;
 8 double inf = 1e15;
 9 int n,m;
10 struct point{
11     int x,y; 
12     point(int x = 0,int y = 0):x(x),y(y){}
13     bool operator < (const point &a)const{return (x==a.x)?y<a.y:x<a.x;}
14     point operator - (const point &a){return point(x-a.x,y-a.y);}
15 }p[N],ch[N];
16 char gc(){
17     static char *p1,*p2,s[1000000];
18     if(p1==p2) p2=(p1=s)+fread(s,1,1000000,stdin);
19     return(p1==p2)?EOF:*p1++;
20 }
21 int rd(){
22     int x = 0,f = 1; char c = gc();
23     while(c<'0'||c>'9') {if(f=='-') f = -1; c = gc();}
24     while(c>='0'&&c<='9') x = x * 10 + c -'0',c = gc();
25     return x * f;  
26 }
27 const double eps = 1e-8;
28 int dcmp(double x){return (fabs(x)<eps)?0:x<0?-1:1;}
29 ll cross(point a,point b){return 1ll*a.x*b.y - 1ll*b.x*a.y;}
30 void convexhull(){
31     sort(p+1,p+n+1);
32     for(int i = n;i>=1;i--){
33         while(m>1&&dcmp(cross(ch[m]-ch[m-1],p[i]-ch[m])<=0)) m--;
34         ch[++m] = p[i];
35     }
36 }
37 double K(point a,point b){return 1.0*(a.y-b.y)/(a.x-b.x);}
38 double calc(double k,point a){return a.x+a.y-1/k*a.y-k*a.x;}
39 int main()
40 {    //freopen("bzoj4570.in","r",stdin);
41     //freopen("bzoj4570.out","w",stdout);
42     n = rd();
43     for(int i = 1,A,B;i <= n;i++) {
44         A = rd(); B = rd();
45         p[i] = point(B,A);
46     }
47     convexhull();
48     double ans = inf;
49     for(int i = 1;i <= m;i++){
50         double k1 = (i!=m)?K(ch[i],ch[i+1]):0;
51         double k2 = (i!=1)?K(ch[i],ch[i-1]):-inf;
52         double k = -sqrt(1.0 * ch[i].y / ch[i].x);
53         if(dcmp(k1-k)>=0&&dcmp(k-k2)>=0) 
54         ans = min(ans,calc(k,ch[i]));
55         if(i!=m&&ch[i+1].y<ch[i].y) break;
56         if(i!=m) ans = min(ans,calc(k1,ch[i]));
57     }
58     printf("%.4lf\n",ans);
59     return 0;
60 }//by tkys_Austin;

 

 

 

posted @ 2018-03-26 07:42  大米饼  阅读(229)  评论(0编辑  收藏  举报