切蛋糕

蛋糕问题最优解法
本文介绍了一个关于蛋糕问题的算法,旨在寻找连续的k块蛋糕,使得这些蛋糕的幸运值之和达到最大。通过使用单调队列维护区间的最小前缀和,实现了高效求解最大区间和的目标。

题目描述

今天是小Z的生日,同学们为他带来了一块蛋糕。这块蛋糕是一个长方体,被用不同色彩分成了N个相同的小块,每小块都有对应的幸运值。

小Z作为寿星,自然希望吃到的第一块蛋糕的幸运值总和最大,但小Z最多又只能吃M小块(M≤N)的蛋糕。

吃东西自然就不想思考了,于是小Z把这个任务扔给了学OI的你,请你帮他从这N小块中找出连续的k块蛋糕(k≤M),使得其上的幸运值最大。

输入输出格式

输入格式

输入文件cake.in的第一行是两个整数N,M。分别代表共有N小块蛋糕,小Z最多只能吃M小块。

第二行用空格隔开的N个整数,第i个整数Pi代表第i小块蛋糕的幸运值。

输出格式

输出文件cake.out只有一行,一个整数,为小Z能够得到的最大幸运值。

输入输出样例

输入样例

样例输入1
5 2
1 2 3 4 5

样例输入2
6 3
1 -2 3 -4 5 -6

输出样例

样例输出1
9

样例输出2
5

题解

一道求最大不定长区间和的问题
区间[i,j]和的最大值ans(i,j)=max{sum[j]-sum[i-1],j-m<i<=j}(其中sum[j]是前缀和数组),我们可以选择去枚举右端点,那么sum[j]就是定值,上面的方程可以化简为ans(i,j)=sum[j]-min{sum[i-1],j-m<i<=j},这样只需要用单调队列维护区间内最小的sum[i-1]就好了

代码

#include<cstdio>
#include<cstring>

const int MAXN=500050;
struct T
{
    int v,pos;
}q[MAXN];

int sum[MAXN],a[MAXN],m,n,ans;

int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

inline int maxx(int x,int y){return x>y?x:y;}

int main()
{
    n=read();
    m=read();
    for(int i=1;i<=n;++i)
    {
        a[i]=read();
        sum[i]=sum[i-1]+a[i];
    }
    int head=0,tail=1;
    q[tail].v=sum[1];
    q[tail].pos=1;
    ans=sum[1];
    for(int i=2;i<=n;++i)
    {
        while(head!=tail&&q[tail].v>sum[i])
            --tail;
        q[++tail].v=sum[i];
        q[tail].pos=i;
        while(head!=tail&&q[head+1].pos<i-m)
            ++head;
        ans=maxx(sum[i]-q[head+1].v,ans);
    }
    printf("%d\n",ans);
    return 0;
}

转载于:https://www.cnblogs.com/dustbin/p/6720509.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值