第一行两个空格隔开的正整数n和d,分别表示关数和相邻僵尸间的距离。接下来n行每行两个空格隔开的正整数,第i + 1行为Ai和 Xi,分别表示相比上一关在僵尸队列排头增加血量为Ai 点的僵尸,排头僵尸从距离房子Xi米处开始接近。
一个数,n关植物攻击力的最小总和 ,保留到整数。
第一关:距离房子3米处有一只血量3点的僵尸,植物最小攻击力为1.00000; 第二关:距离房子1米处有一只血量1点的僵尸、3米处有血量3点的僵尸,植物最小攻击力为1.33333; 第三关:距离房子8米处有一只血量10点的僵尸、10米处有血量1点的僵尸、12米处有血量3点的僵尸,植物最小攻击力为1.25000; 第四关:距离房子8米处有一只血量4点的僵尸、10米处有血量10点的僵尸、12米处有血量1点的僵尸、14米处有血量3点的僵尸,植物最小攻击力为1.40000; 第五关:距离房子3米处有一只血量2点的僵尸、5米处有血量4点的僵尸、7米处有 血量10点的僵尸、9米处有血量1点的僵尸、11米处有血量3点的僵尸,植物最小攻击力 为2.28571。 植物攻击力的最小总和为7.26905。
对于100%的数据, 1≤n≤10^5,1≤d≤10^12,1≤x≤ 10^12,1≤a≤10^12
凸包+三分,思路好
sum[i]表示a[i]的前缀和。
可以把每一个僵尸和他前面僵尸的力量叠加起来考虑,这样每个僵尸从一开始就是受伤害的,而他必须在靠近房子之前被打死。
所以有:y[i]=max{(sum[i]-sum[j-1])/(x[i]+(i-j)*d)},j≤i。
如果暴力计算是n^2的,显然不能过。
这里有一个思路很好的优化:
我们看这个公式,发现很想斜率的形式。令y1=sum[i],y2=sum[j-1],x1=x[i]+i*d,y2=j*d,k=(y1-y2)/(x1-x2)。所以我们就是要求P(x1,y1)和Q(x2,y2)连线斜率的最大值。
每一关的P点是不一样的,但Q点是定值。
于是问题变成每次加入一个点,然后给出一个P点,询问P点和这些点的连线斜率的最大值。因为P一定在这些点右上方,所以维护一个下凸包,每次在凸包上三分即可。
注意整数三分和实数三分写法的不同:while(r-l>=3) ……
#include<iostream> #include<cstdlib> #include<cmath> #include<cstring> #include<cstdio> #include<algorithm> #define F(i,j,n) for(int i=j;i<=n;i++) #define D(i,j,n) for(int i=j;i>=n;i--) #define ll long long #define maxn 100005 #define inf 1e30 using namespace std; int n,head,tail,q[maxn]; ll d,sum[maxn],a[maxn]; double ans; inline ll read() { ll x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } double getk(int x,int y) { return (double)(sum[x-1]-sum[y-1])/(double)(d*x-d*y); } double getk2(int x,int y) { return (double)(sum[x]-sum[y-1])/(double)(a[x]+d*x-d*y); } double sanfen(int x) { int l=head,r=tail,lmid,rmid; while (r-l>=3)//注意整数三分与实数三分的区别 { lmid=l+(r-l)/3;rmid=r-(r-l)/3; if (getk2(x,q[lmid])<getk2(x,q[rmid])) l=lmid; else r=rmid; } double ret=-inf; F(i,l,r) ret=max(ret,getk2(x,q[i])); return ret; } int main() { n=read();d=read(); F(i,1,n) sum[i]=sum[i-1]+read(),a[i]=read(); head=1;tail=0; F(i,1,n) { while (head<tail&&getk(q[tail-1],q[tail])>getk(q[tail],i)) tail--; q[++tail]=i; ans+=sanfen(i); } printf("%.0lf\n",ans); return 0; }