[JZOJ5451]【NOIP2017提高A组冲刺11.4】Genocide

来源:互联网 发布:linux怎么打开found 编辑:程序博客网 时间:2024/06/03 20:07

Description

这里写图片描述
这里写图片描述

Solution

50分的非常简单,原式可以拆成一个斜率的式子,我们可以用一个单调栈进行斜率优化(为什么是栈而不是队列,可以自行画个图)

考虑100分
对于某一个点的更改,只需要求出必须选这个点的最优答案和不选这个点的最优答案。

不选这个点的答案非常好求,可以倒过来做一遍DP
fi表示1到i的答案,gi表示i到N的答案
那么不选的答案就是fi1+gi+1

难点在于选。

hx表示选x这个点的答案。
可以得出hx=max(fi+gj+(ij)(ij1)/2sum[j1]+sum[i]),i<x<j
其中sum为费用的前缀和

暴力匹配显然超时
考虑一次性将所有的位置的h求出来

CDQ分治!
对于处理区间[L,R],考虑mid左边的i,mid右边所有的j对mid左边的x的贡献。

可以发现mid右边的所有j都可以弄到一个栈里,和之前的斜率优化非常相似(几乎一模一样)

然后左边相应的扫,扫到一个位置就更新它的h,相应的弹栈

对于mid右边的x,做法完全一样,只需要倒过来做,把左边的i扔到栈里,右边倒过来扫
式子推的比较恶心,还要处理变号等一系列问题(我就是受害者

其实可以全部做完以后将序列翻转重新做一次,那么之前的代码可以再次利用,不需要重新推导。
复杂度O(NlogN)

Code

#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <iostream>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fod(i,a,b) for(int i=a;i>=b;i--)#define N 300005#define LL long longusing namespace std;int n,m,d[N],l,r;LL f[N],a[N],sum[N],c[N],g[N],f1[N],g1[N],h[N];LL xl(LL k){    return f[k]+(k-1)*k/2+sum[k];}LL xl2(LL k){    return g[k]+(k+1)*k/2-sum[k-1];}void cdq(int l,int r){    if(l==r) return;    int top=0;    int mid=(l+r)/2;    fo(i,mid+1,r)     {        while(top>1&&(g1[i]-g1[d[top]])*(LL)(d[top]-d[top-1])>=(g1[d[top]]-g1[d[top-1]])*(LL)(i-d[top])) top--;        d[++top]=i;    }    LL mx=-1e15;    fo(i,l,mid-1)    {        while(top>1&&(g1[d[top]]-g1[d[top-1]])<=(LL)i*(LL)(d[top]-d[top-1])) top--;        mx=max(mx,(f1[i]+g1[d[top]])-(LL)i*d[top]);        h[i+1]=max(h[i+1],mx);    }    top=0;    fod(i,mid,l)    {        while(top>1&&(f1[i]-f1[d[top]])*(LL)(d[top]-d[top]-1)<=(f1[d[top]]-f1[d[top-1]])*(LL)(i-d[top])) top--;        d[++top]=i;    }    mx=-1e15;    fod(i,r,mid+2)    {        while(top>1&&(f1[d[top]]-f1[d[top-1]])<=(LL)i*(LL)(d[top]-d[top-1])) top--;        mx=max(mx,(f1[d[top]]+g1[i])-(LL)i*d[top]);        h[i-1]=max(h[i-1],mx);    }    cdq(l,mid),cdq(mid+1,r);}int main(){    cin>>n;    fo(i,1,n) scanf("%lld",&a[i]),sum[i]=a[i]+sum[i-1];    cin>>m;    l=0,r=0;    fo(i,1,n)    {        while(l<r&&xl(d[r])-xl(d[r-1])<=(LL)i*(LL)(d[r]-d[r-1])) r--;        f[i]=max(f[i-1],f[d[r]]+(LL)(i-d[r])*(LL)(i-d[r]+1)/2-sum[i]+sum[d[r]]);        while(l<r&&(xl(i)-xl(d[r]))*(LL)(d[r]-d[r-1])>=(xl(d[r])-xl(d[r-1]))*(LL)(i-d[r])) r--;        d[++r]=i;        f1[i]=(f[i]+(LL)i*(i+1)/2+sum[i]);    }    f1[0]=0;    l=0,r=0;    d[0]=n+1;    memset(h,128,sizeof(h));    fod(i,n,1)    {        while(l<r&&xl2(d[r])-xl2(d[r-1])<=(LL)i*(LL)(d[r]-d[r-1])) r--;        g[i]=max(g[i+1],g[d[r]]+(LL)(d[r]-i)*(LL)(d[r]-i+1)/2+sum[i-1]-sum[d[r]-1]);        while(l<r&&(xl2(i)-xl2(d[r]))*(LL)(d[r]-d[r-1])<=(xl2(d[r])-xl2(d[r-1]))*(LL)(i-d[r])) r--;        d[++r]=i;        g1[i]=(g[i]+(LL)i*(i-1)/2-sum[i-1]);    }    g1[n+1]=(LL)(n+1)*(n)/2-sum[n];    if(f[n]!=g[1]) printf("WA");    cdq(0,n+1);    fo(q,1,m)    {        int x,y;        scanf("%d%d",&x,&y);        printf("%lld\n",max(h[x]-(y-a[x]),f[x-1]+g[x+1]));    }}
原创粉丝点击