Atcoder Regular Contest 066 F genocide【JZOJ5451】

来源:互联网 发布:mac用pe安装win7系统 编辑:程序博客网 时间:2024/06/08 18:59

题目

这里写图片描述

分析

s[i]表示a前缀和。
f[i]表示做完了1~i的友谊颗粒的最优值(不一定选i),那么转移方程为

f[i]=max{f[i1],max{f[j]s[i]+s[j]+(ij)(ij+1)2}}
,用斜率优化来处理这个。
类似的,设gi表示做完了i~n的友谊颗粒的最优值(不一定选i),
将a翻转,像f一样做一遍,再将g翻转就可以了。
对于询问(p,x),如果我们不选择p,那么答案就是f[i1]+g[i+1]
如果我们选择了p,我们再设F[i]表示,必选i的最优值。
F[i]=max{f[j]+g[k]+(kj+1)(kj+2)2}(j<i<k)

时间复杂度是O(N2)
如何可以更快的求出F[i]呢,
分治,假设当前做到[l,r],左端点[l,mid],i和右端点在[mid+1,r]
tmp[i]表示做完了左端点~i的友谊颗粒,且必选i的最优值
我们将[l1,mid1]的端点扔进斜率优化的单调栈,扫一遍[mid+1,r]求出tmp,
tmp[i]=max{f[j]+g[i+1]+(ij+1)(ij+2)2}(j[l1,mid1]<i[mid+1,r])

那么F[i]就是当前区间tmp[i]的后缀max
因为只考虑了i在[mid+1,r]的情况,反过来做一遍就可以了。
那么选择了p的的最优值就是F[p]+a[p]x

#include <iostream>#include <cmath>#include <cstring>#include <algorithm>#include <cstdio>#include <cstdlib>#include <map>#include <queue>#include <stack>using namespace std;const int maxlongint=2147483647;const int mo=1e9+7;const int N=1000005;#define rev(h) for(int i=1;i<=n/2;i++) swap(h[i],h[n-i+1])#define val(h,j,k) 1ll*(h[j]-h[k]+s[j]-s[k]-1ll*j*1.0/2+1ll*k*1.0/2+1ll*j*j*1.0/2-1ll*k*k*1.0/2)*1.0/(j-k)int n,m,t[N],top;long long a[N],s[N],f[N],g[N],F[N],tmp[N];void dg(long long *f,long long *g,int l,int r){    if(l==r)    {        F[l]=max(F[l],f[l-1]+g[l+1]+1-a[l]);        return;    }    int mid=(l+r)>>1;    top=0;    for(int i=l-1;i<=mid;i++)    {        for(;top>1 && val(f,i,t[top])>=val(f,t[top],t[top-1]);) top--;        t[++top]=i;    }    for(int i=mid+1;i<=r;i++)    {        for(;top>1 && val(f,t[top],t[top-1])<=i;) top--;        int j=t[top];        tmp[i]=f[j]-(s[i]-s[j])+1ll*(i-j)*(i-j+1)/2+g[i+1];    }    for(int i=r-1;i>=mid+1;i--) tmp[i]=max(tmp[i],tmp[i+1]);    for(int i=r;i>=mid+1;i--) F[i]=max(F[i],tmp[i]);    dg(f,g,l,mid),dg(f,g,mid+1,r);}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++) scanf("%lld",&a[i]),s[i]=s[i-1]+a[i],F[i]=-a[i]+1;    t[top=1]=0;    for(int i=1;i<=n;i++)    {        for(;top>1 && val(f,t[top],t[top-1])<=i;) top--;        int j=t[top];        f[i]=max(f[j]-(s[i]-s[j])+1ll*(i-j)*(i-j+1)/2,f[i-1]);        for(;top>1 && val(f,i,t[top])>=val(f,t[top],t[top-1]);) top--;        t[++top]=i;    }    rev(a);    t[top=1]=0;    for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];    for(int i=1;i<=n;i++)    {        for(;top>1 && val(g,t[top],t[top-1])<=i;) top--;        int j=t[top];        g[i]=max(g[j]-(s[i]-s[j])+1ll*(i-j)*(i-j+1)/2,g[i-1]);        for(;top>1 && val(g,i,t[top])>=val(g,t[top],t[top-1]);) top--;        t[++top]=i;    }    rev(a);    for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];    rev(g);    dg(f,g,1,n);    rev(a);    rev(g);    for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];    rev(F);    rev(f);    dg(g,f,1,n);    rev(F);    rev(g);    rev(f);    rev(a);    scanf("%d",&m);    for(int i=1;i<=m;i++)    {        long long p,x;        scanf("%lld%lld",&p,&x);        printf("%lld\n",max(f[p-1]+g[p+1],F[p]+a[p]-x));    }}
原创粉丝点击