OJ掛,鏈自找
由題目的特性可知,我們可以把血量求前綴和,然後視爲同時攻擊
則每次的可以表示爲
直接求就是
考慮優化,發現如果我們把i分離出來,式子就變成了
妥妥的斜率式子
即兩個點連線的斜率
並且第一個點始終在所有合法對應的點的右上方
那麼維護一個的對應點的下凸殼,則答案就是單峯的,三分即可,也可以差分了做二分
Code:
#include<bits/stdc++.h>
#define db double
#define ll long long
using namespace std;
inline ll read(){
ll res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int N=1e5+5;
struct point{
ll x,y;
point(){}
point(ll _x,ll _y):x(_x),y(_y){}
friend inline db slp(const point &a,const point &b){return 1.0*(a.y-b.y)/(a.x-b.x);}
}sta[N];
int n,top;
ll x[N],a[N],d;
db ans=0.0;
int main(){
n=read();d=read();
for(int i=1;i<=n;i++) a[i]=a[i-1]+read(),x[i]=read();
for(int i=1;i<=n;i++){
point tmp=point(d*i,a[i-1]);
while(top && slp(sta[top-1],sta[top])>slp(sta[top],tmp)) --top;
sta[++top]=tmp;
tmp=point(x[i]+d*i,a[i]);
int l=1,r=top,res=0;
while(l<=r){
int mid=l+r>>1;
if(slp(sta[mid-1],tmp)<slp(sta[mid],tmp)) res=mid,l=mid+1;
else r=mid-1;
}
ans+=slp(sta[res],tmp);
}
printf("%.0lf",ans);
return 0;
}