【牛客】数学考试 前缀和+思维

题目链接

https://ac.nowcoder.com/acm/problem/15553

题目描述

今天qwb要参加一个数学考试,这套试卷一共有n道题,每道题qwb能获得的分数为ai,qwb并不打算把这些题全做完,
他想选总共2k道题来做,并且期望他能获得的分数尽可能的大,他准备选2个不连续的长度为k的区间,
即[L,L+1,L+2,…,L+k-1],[R,R+1,R+2,…,R+k-1](R >= L+k)

输入

第一行一个整数T(T<=10),代表有T组数据
接下来一行两个整数n,k,(1<=n<=200,000),(1<=k,2k <= n)
接下来一行n个整数a1,a2,…,an,(-100,000<=ai<=100,000)
样例:
2
6 3
1 1 1 1 1 1
8 2
-1 0 2 -1 -1 2 3 -1

输出

输出一个整数,qwb能获得的最大分数
6
7

暴力思路(T了)

对于每一次求取值,都把l和r枚举一遍,然后用前缀和处理掉区间和问题,然后它T了,很显然需要优化

对于枚举的优化

我们每一次是要求两个区间的和为最大,有一个思路就是用更新时间来保证前面的区间最大值一定是后面的区间最大值的前面一段
基本式子为:(其中i为循环到的值)

  1. L=max(L,[i-k+1,i])
  2. sum=max(sum,L+[i+1,i+k])
    这个式子可以同时保证两个条件:
    1.在到i时L是区间【a,b】中b取值从k到i时能取到的最大值
    2.求sum的时候,他取的L是在i+1之前的一个区间上的一个最大值,所以每一次取的时候都满足了前面一段区间在后面一段区间的前面的条件,同时取最大值

代码

#include
#include
using namespace std;
const int maxn=200010;
typedef long long ll;
int a[maxn];
ll qz[maxn];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,k;
        scanf("%d%d",&n,&k);
        qz[0]=0;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            qz[i+1]=qz[i]+a[i];//处理前缀和
        }
        ll L=qz[k]-qz[0],sum=qz[2*k]-qz[0];
        for(int i=k;i+k<=n;i++)
        {
           L=max(L,qz[i]-qz[i-k]);
           sum=max(sum,L+qz[i+k]-qz[i]);
           //printf("L=%lld  ,sum=%lld\n",L,sum);
        }
        printf("%lld\n",sum);
    }
    return 0;
}

你可能感兴趣的:(算法)