题目源自洛谷;
题目大意:
模拟植物大战僵尸的一排,可以理解成豌豆射手对第一个僵尸发射激光,造成持续伤害并且第一个僵尸死后第二个僵尸立马收到伤害。 然后不同的是,有n个回合,每回合在僵尸队列前端会添加一个僵尸,之后的僵尸会往后移动d个距离,n个回合单独计算。求n个回合杀死所有僵尸的最小攻击力(hp/s)。
题目讲解:
首先模拟一下样例,贪心的求:在第i个回合,能杀死前j个僵尸的攻击力,取最大值;数学表达就是
得到公式后,很显然,可以转化为两点求斜率的式子:
即点和;
可以发现对于每回合,第一个点是唯一的,第二类点的个数是随i增大而增多的,但也都是固定的。
这时候此题已经转化为了对于每回合,求第一个点与前i个第2类点连成线段斜率的最大值。
看图我们可以大致猜测一个结论:斜率最大值的点一定在第二类点构成的下凸壳上; 之后我们来简单证明(感谢同校大佬提供的思路,%%%Daowuu):
如图是i=5的时候的第一种点(E) 和第二类点(A、B、C、D),尝试将E也加入凸包中,假设与E相连的点为P,那么与E连线斜率最大的点一定是点P。因为根据凸包的性质可知其他点一定在与PE这条边的内侧,即其他点与E连线的斜率一定小于PE的斜率,证毕。
而此时,凸壳上的点会被分成两部分,一部分是在E加入凸壳后仍然在凸壳边上的点,这些点(x坐标小于P点)的斜率一定小于E,而E加入后可能会弹出一部分点(x坐标大于P点),这些点的斜率也是小于PE的,此时我们会发现在原凸壳上,与E连线的斜率是一个单峰函数。
最后采用三分寻找P点即可。
时间复杂度:
代码:
#include <bits/stdc++.h>
#define int long long
#define eps 0.00000001
using namespace std;
struct Point{
double x,y;
Point(double x=0,double y=0):x(x),y(y){}
};
Point stk[100005];
typedef Point Vector;
Vector operator + (Vector A, Vector B) {return Vector(A.x+B.x,A.y+B.y);}
Vector operator - (Vector A, Vector B) {return Vector(A.x-B.x,A.y-B.y);}
Vector operator * (Vector A, double B) {return Vector(A.x*B,A.y*B);}
Vector operator / (Vector A, double B) {return Vector(A.x/B,A.y/B);}
int dcmp(double x)
{
if(fabs(x)<eps) return 0;
else if(x>0) return 1;
else return -1;
}
double cross(Vector p,Vector q){return p.x*q.y-p.y*q.x;}
int n,d,cnt=0;
double hp,pos,pre[100005];
signed main()
{
scanf("%lld%lld",&n,&d);
double res=0;
for(int i=1;i<=n;i++)
{
scanf("%lf%lf",&hp,&pos);
pre[i]=pre[i-1]+hp;
Point p={i*1.0*d,pre[i-1]},now={pos+i*1.0*d,pre[i]};
while(cnt>1&&dcmp(cross(stk[cnt]-stk[cnt-1],p-stk[cnt]))<0) cnt--;
cnt++;
stk[cnt]=p;
if(cnt==1){
res+=(hp/pos);
}else{
int left=1,right=cnt;
while(left+10<right)
{
int mid=(left+right)/2;
int midr=(mid+right)/2;
double k1=(now.y-stk[mid ].y)/(now.x-stk[mid ].x);
double k2=(now.y-stk[midr].y)/(now.x-stk[midr].x);
if(k1>k2) right=midr;
else if(k1<k2) left=mid;
}
double maxd=0;
for(int j=left;j<=right;j++)
{
double temp=(now.y-stk[j].y)/(now.x-stk[j].x);
maxd=max(maxd,temp);
}
res+=maxd;
}
}
printf("%.0lf\n",res);
return 0;
}