AtCoder Regular Contest 066 F Contest with Drinks Hard

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/qq_35950004/article/details/81543076

题意:一个长度为n的数组,选出其中几项,要最大化sigma( 1 , 1 <= L <= R <= n 且 对于L<=i<=R的i都被选中 ) - sigma( val[i] , i被选中) , 并回答q次询问 : 只有val[i]改变为k时的最大值。

不考虑改变时,可以斜率优化。
改变时,分别计算选和不选i的最大值再处理选的值就行。
不选i的最大值就是正反两次dp相加,
选i的最大值可以通过cdq分治,
每次处理必选x(mid<=x<=r),且x所在选择区间左端点在(l,mid),右端点在(mid,r)的答案,先求出以每个点为右端点的答案,再做一遍后缀最大值,就能求出每个x的答案。

初始值为负无穷大 , 正反都要dp,逆转数组时注意能否直接翻转。

AC code:

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#define maxn 300005
#define LL long long
using namespace std;

int n,m;
LL cst[maxn],f[maxn],g[maxn],y[maxn],Q[maxn],sum[maxn],h[maxn],tmp[maxn],L,R;
inline bool check1(int a,int b,int k){
    return y[b] - y[a] < 1ll * (b - a) * k; }
inline bool check2(int a,int b,int k){ return 1ll * (k - b) * (y[k] - y[a]) - 1ll * (k - a) * (y[k] - y[b]) < 0; }
inline void shift(int b,int a,LL f[])
{

    f[b] = max(f[b] , f[a] + 1ll * (b - a) * (b - a + 1) / 2ll - sum[b] + sum[a]);

}

void DP(LL f[])
{
    L=R=0,Q[R++] = 0;
    for(int i=1;i<=n;i++)
    {
        sum[i] = sum[i-1] + cst[i];
        for(;L<R-1 && check1(Q[R-2],Q[R-1],i);R--);
        f[i] = f[i-1];
        shift(i,Q[R-1],f);
        y[i] = f[i] + 1ll * i * (i-1) / 2 + sum[i];
        for(;L<R-1 && check2(Q[R-2],Q[R-1],i);R--);
        Q[R++] = i;
    }
}

inline void Rev(LL f[]){ for(int i=1;i<=n/2;i++) swap(f[i] , f[n-i+1]); }

void Solve(LL *f,LL *g,int l,int r)
{
    if(l==r){ h[l] = max(h[l] , f[l-1] + g[l+1] - cst[l] + 1); return; }
    if(l>r) return;
    int mid = (l+r)>>1;
    L=R=0;
    for(int i=l-1;i<=r;i++)
    {
        for(;L<R-1 && check2(Q[R-2],Q[R-1],i);R--);
        if(i<mid) Q[R++] = i , tmp[i] = f[i];
        else tmp[i] = -0x3f3f3f3f3f3f3f3f , tmp[i] = max(tmp[i] , f[Q[R-1]] + 1ll * (i - Q[R-1]) * (i - Q[R-1] + 1) / 2ll - sum[i] + sum[Q[R-1]] + g[i+1]);
    }

    for(int i=r-1;i>=mid;i--) tmp[i] = max(tmp[i] , tmp[i+1]);
    for(int i=r;i>=mid;i--) h[i] = max(h[i] , tmp[i]);

    Solve(f,g,l,mid) , Solve(f,g,mid+1,r);
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&cst[i]);
    scanf("%d",&m);

    Rev(cst) , DP(g) , Rev(g) , Rev(cst) , DP(f);
    memset(h,-0x3f,sizeof h);
    Solve(f,g,1,n);
    Rev(cst) , Rev(g) , Rev(f) , Rev(h);
    for(int i=1;i<=n;i++) sum[i] = sum[i-1] + cst[i] , y[i] = g[i] + 1ll * i * (i-1) / 2 + sum[i];
    Solve(g,f,1,n);
    Rev(h) , Rev(f) , Rev(g) , Rev(cst);


    for(int u,v;m--;)
    {
        scanf("%d%d",&u,&v);
        printf("%lld\n",max(f[u-1] + g[u+1] , h[u] - (v - cst[u])));
    }
}

猜你喜欢

转载自blog.csdn.net/qq_35950004/article/details/81543076