看了好多dalao们的题解,然而还是不明白...
于是在想了半天后,决定自己写一篇题解。
因此,我们只需要找到一个\(j\),使得找不到\(k\)满足上面的式子,
那么这个\(j\)就是最优解了。
即:
设\(y\)是\(i\)的最优解 ,
那么对于任意满足\(d_x\)\(<\)\(d_y\)\(<\)\(d_z\)(等于时要特判)的\(x\),\(z\),
都有\(\frac{v_y-v_x}{d_y-d_x}\)\(>\)\(a_i\)\(>\)\(\frac{v_y-v_z}{d_y-d_z}\),
因此,对于\(l\)~\(mid\),我们先将\(d\)按升序排列,
再用单调队列维护\(\frac{v_y-v_x}{d_y-d_x}\)的降序排列(蒟蒻的单调队列讲得似乎有点不清楚自己理解下哈)
同时,对于\(mid\)+\(1\)~\(r\)为了节省时间,将\(a\)按降序排列(所以多开几个数组),
每次在单调队列中找出第一个小于\(a_i\)的\(\frac{v_y-v_x}{d_y-d_x}\),
再用\(y\)更新\(i\)的答案就行了。
对于\(d\)和\(a\)的排序,归并时排一下就可以解决。
具体实现方式看代码吧:
#include<bits/stdc++.h>
#define db double
#define ll long long
using namespace std;
inline int read(){
    ll sum=0,f=1;char ch=getchar();
    while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    return f*sum;
}
struct node{
    int a/*攻击*/,d/*被打次数*/;
    ll v/*被秒掉后下降的伤害*/;
}c[500001]/*敌方*/,q1[500001]/*按d升序排列*/,q2[500001]/*按a降序排列*/;
node qq[500001];//排序时临时存一下
int n,atk;
ll ans=0,ansn=0;
ll sa[500001]/*被打次数的前缀和*/,sb[500001]/*攻击的后缀和*/;
int q[500001];
bool cmp(node x,node y){
    return (ll)x.d*y.a<(ll)y.d*x.a;
}
db cmp1(int x,int y){
    if(q1[x].d==q1[y].d){
        if(q1[y].v<=q1[x].v) return 0;
        return 1e18;
    }
    return (db)((q1[y].v-q1[x].v)/(q1[y].d-q1[x].d));
}
void CDQ(int l,int r){
    if(l==r) return ;
    int mid=(l+r)>>1;
    CDQ(l,mid);CDQ(mid+1,r);
    int le=1,ri=0;
    for(int i=l;i<=mid;i++){
        while(le<ri&&cmp1(q[ri-1],q[ri])<cmp1(q[ri],i)) ri--;
        q[++ri]=i;
    }
    for(int i=mid+1;i<=r;i++){
        while(le<ri&&cmp1(q[le],q[le+1])>=q2[i].a) le++;
        ans=max(ans,(ll)(q2[i].v+q1[q[le]].v-q2[i].a*q1[q[le]].d));
    }
    int pi=l,qi=mid+1,tot=l;
    while(pi<=mid&&qi<=r){
        if(q1[pi].d<q1[qi].d) qq[tot++]=q1[pi++];
        else qq[tot++]=q1[qi++];
    }
    while(pi<=mid) qq[tot++]=q1[pi++];
    while(qi<=r) qq[tot++]=q1[qi++];
    for(int i=l;i<=r;i++) q1[i]=qq[i];
    pi=l,qi=mid+1,tot=l;
    while(pi<=mid&&qi<=r){
        if(q2[pi].a>q2[qi].a) qq[tot++]=q2[pi++];
        else qq[tot++]=q2[qi++];
    }
    while(pi<=mid) qq[tot++]=q2[pi++];
    while(qi<=r) qq[tot++]=q2[qi++];
    for(int i=l;i<=r;i++) q2[i]=qq[i];
}
int main(){
    freopen("fight.in","r",stdin);
    freopen("fight.out","w",stdout);
    n=read();atk=read();
    for(int i=1;i<=n;i++){
        c[i].a=read();c[i].d=read();
        c[i].d=(c[i].d-1)/atk+1;
    }
    sort(c+1,c+n+1,cmp);
    for(int i=1;i<=n;i++) sa[i]=sa[i-1]+c[i].d;
    for(int i=n;i>=1;i--) sb[i]=sb[i+1]+c[i].a;
    for(int i=1;i<=n;i++) ansn+=c[i].a*(sa[i]-1);
    for(int i=1;i<=n;i++){
        c[i].v=(sa[i]-1)*c[i].a+sb[i+1]*c[i].d;
    }
    for(int i=1;i<=n;i++) q1[i]=c[i],q2[i]=c[i];
    CDQ(1,n);
    printf("%lld\n",ansn-ans);
    return 0;
}原文:https://www.cnblogs.com/zsq259/p/10575314.html