运气糖果
Description
今天ZJZJZJ学长想转运,所以某某为他带来NNN颗运气糖果。
每颗运气糖果都有不同的幸运值。
既然ZJZJZJ学长想转运,自然希望自己的运气越来越好了,但ZJZJZJ学长最多又只能吃MMM颗(M≤NM \leq NM≤N)糖果。
而且吃东西自然就不想思考了,于是ZJZJZJ学长把这个任务扔给了学acmacmacm的你,请你帮他从这NNN颗糖果中找出连续的kkk颗糖果(k≤Mk \leq Mk≤M),使得ZJZJZJ学长可以得到最大的幸运值。
Input
输入格式
第一行包含两个整数NNN和MMM,表示共有NNN颗糖果,ZJZJZJ最多只能吃MMM颗。
第二行包含空格隔开的NNN个整数,第iii个整数PiPiPi代表第i颗糖果的幸运值。
Output
输出格式
输出包含一个整数,为ZJ能够得到的最大幸运值。
数据范围
1≤M≤N≤10001 \leq M \leq N \leq 10001≤M≤N≤1000,
−1000≤Pi≤1000−1000 \leq Pi \leq 1000−1000≤Pi≤1000
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;
}