运气糖果(前缀和单调递增队列维护)

运气糖果

Description

今天ZJZJZJ学长想转运,所以某某为他带来NNN颗运气糖果。

每颗运气糖果都有不同的幸运值。

既然ZJZJZJ学长想转运,自然希望自己的运气越来越好了,但ZJZJZJ学长最多又只能吃MMM颗(M≤NM \leq NMN)糖果。

而且吃东西自然就不想思考了,于是ZJZJZJ学长把这个任务扔给了学acmacmacm的你,请你帮他从这NNN颗糖果中找出连续的kkk颗糖果(k≤Mk \leq MkM),使得ZJZJZJ学长可以得到最大的幸运值。

Input

输入格式

第一行包含两个整数NNNMMM,表示共有NNN颗糖果,ZJZJZJ最多只能吃MMM颗。

第二行包含空格隔开的NNN个整数,第iii个整数PiPiPi代表第i颗糖果的幸运值。

Output

输出格式

输出包含一个整数,为ZJ能够得到的最大幸运值。

数据范围

1≤M≤N≤10001 \leq M \leq N \leq 10001MN1000,
−1000≤Pi≤1000−1000 \leq Pi \leq 10001000Pi1000

Sample Input 1

5 2
1 2 3 4 5

Sample Output 1

9

Source

yzj

思路

  • 题意:这一题让求,在一个长度为n的序列中,我们要选择一个长度为 <= m 的子串,是这个子串的和的值最大(序列值可能为负),⚠️如果过序列值全是负值的话,我们可以选择一个也不吃(即选择子串的长度为0)
  • 思路:对于连续的子串问题我们可以用 前缀和 来进行优化操作, 这一题的难点就是 我们要选择的子串长度小于等于m,如果我是 只等于m的话我们就直接 用尺取维护就行了, 但是偏偏子串长度是可以小于m的,这个问题我们可以用 维护一个 长度等于m的单调递增的 前缀和队列,那么对于这个队列,在它的 队头位置,一定是最小前缀和,每次在往队列中添加 前缀和的时候,不断将这个前缀 减去 队头的前缀和,不断位置这个最大差值

题解(暴力 小数据 O n^2)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;

#define db double
#define ll long long 

const int Len = 1e6 + 5;
ll sum[Len];

int main()
{
    //freopen("A.txt","r",stdin);
    ll n,m;
    scanf("%lld %lld", &n, &m);
    for(int i = 1; i <= n; i ++)
        scanf("%lld", &sum[i]), sum[i] += sum[i-1];
    ll mx = -1e9;
    for(int i = 1; i <= m; i ++)
        for(int j = i; j <= n; j ++)
            mx = max(mx, sum[j] - sum[j - i]);
    printf("%lld\n", mx);

    return 0;
}

题解(On)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<climits>
using namespace std;

const int Len = 1e6 +10;
int ar[Len];
int q[Len];

int Work(int n, int m)
{
    //维护一个单调递增的序列
    int head = 0, tail = 0;
    int res = INT_MIN;
    for(int i = 0; i <= n; i ++)        //这里 i 要从0 开始因为如果全是负数,我们可以一块也不吃,那么幸运值就是0
    {
        while(head <= tail && q[head] < i - m) head ++;     //这里一定是q小于 i-m,因为 i - m 已经这个下标位置 已经是边界了(最大范围是 sum[i] - sum[i - m]) 
        res = max(res, ar[i] - ar[q[head]]);
        while(head <= tail && ar[q[tail]] >= ar[i]) tail --;    //⚠️ 这里下标要 >= 这一题是最多只能吃 m 个的限制
        q[++ tail] = i;
    }
    return res;  
}

int main()
{
    //freopen("A.txt","r",stdin);
    int n,m;
    scanf("%d %d", &n, &m);
    for(int i = 1; i <= n; i ++)
        scanf("%d", &ar[i]), ar[i] += ar[i - 1];
    printf("%d\n", Work(n, m));

    return 0;
}


发布了149 篇原创文章 · 获赞 228 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_34261446/article/details/105152054