题解 P1714 【切蛋糕】

· · 个人记录

我一开始以为这题就是普通的线段树求区间和,于是愉快地打起了板子。

然后发现事情好像不是这样的。。。。。。(血崩)k是1~m的,而且蛋糕还有负数幸运值(卧槽毒奶做的蛋糕?)

打开了题解冥思苦想,线段树实现的话需要枚举左右端点,复杂度是O(N^2),明显过不了,我们需要O(N)的复杂度。

如果用前缀和进行预处理,然后我们只需要枚举右端点,然后在范围内用线段树求出左端点就ok啦,虽然不是O(N)的复杂度,但是也刚好是符合题目的蛋糕范围的。

贴上我最喜欢的线段树代码(雾)(我怎么又交了一个线段树题解?)

#include <bits/stdc++.h>
using namespace std;

int n;
long long minn[4000000];
int a[1000000];
long long c[1000000];

void build(int l,int r,int id)
{
    if(l==r)
    {
        minn[id]=c[l];
        return ;
    }
    int mid=(l+r)/2;
    build(l,mid,id*2);
    build(mid+1,r,id*2+1);
    minn[id]=min(minn[id*2],minn[id*2+1]);
}

long long cck(int l,int r,int z,int y,int id)
{
    if(l==z&&r==y)
    {
        return minn[id];
    }
    int mid=(l+r)/2;
    if(mid>=y)return cck(l,mid,z,y,id*2);
    else if(mid<z)return cck(mid+1,r,z,y,id*2+1);
    else return min(cck(l,mid,z,mid,id*2),cck(mid+1,r,mid+1,y,id*2+1));
}

long long maxn;
int k;
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        c[i]=c[i-1]+a[i];
    }
    build(1,n,1);
    for(int i=1;i<=n;i++)
    {
        maxn=max(c[i]-cck(1,n,max(i-k,1),i,1),maxn);
    }
    printf("%d\n",maxn);
    return 0;
}