清北学堂模拟赛d2t4 最大值(max)

题目描述
LYK有一本书,上面有很多有趣的OI问题。今天LYK看到了这么一道题目:
这里有一个长度为n的正整数数列ai(下标为1~n)。并且有一个参数k。
你需要找两个正整数x,y,使得x+k<=y,并且y+k-1<=n。并且要求a[x]+a[x+1]+…+a[x+k-1]+a[y]+a[y+1]+…+a[y+k-1]最大。
LYK并不会做,于是它把题扔给了你。

输入格式(max.in)
第一行两个数n,k。
第二行n个数,表示ai。

输出格式(max.out)
两个数表示x,y。若有很多种满足要求的答案,输出x最小的值,若x最小仍然还有很多种满足要求的答案,输出y最小的值。

输入样例
5 2
6 1 1 6 2

输出样例
1 4

对于30%的数据n<=100。
对于60%的数据n<=1000
对于100%的数据1<=n<=100000,1<=k<=n/2,1<=ai<=10^9。

分析:一个O(n^3)的做法,直接枚举两个区间,再枚举求区间和.因为用到了区间和,所以可以用前缀和优化到O(n^2).然后可以发现这个区间长度是固定的,我们可以在挪动右端点的时候右边每加一个数,左边弹一个数,用O(n)的时间处理出每一段长度为k的区间的和,在处理的过程中可以顺便记录j-k之前的区间最大值,一边求和一边统计答案就可以了.

#include <bits/stdc++.h>

using namespace std;

int n,k,lastt = 1,x,y;
long long a[100010],r[100010],Max,sum,ans;

int main()
{
    freopen("max.in","r",stdin);
    freopen("max.out","w",stdout);
    scanf("%d%d",&n,&k);
    for (int i = 1; i <= n; i++)
        scanf("%lld",&a[i]);
    for (int i = 1; i <= n; i++)
    {
        sum += a[i];
        if (i - k > 0)
            sum -= a[i - k];
        r[i] = sum;
        if (i - k > 0)
        {
            if (Max < r[i - k])
            {
                Max = max(Max,r[i - k]);
                lastt = i - k;
            }
        }
        if (Max + r[i] > ans)
        {
        ans = max(ans,Max + r[i]);
        x = max(1,lastt - k + 1);
        y = max(1,i - k + 1);
        }
    }
    printf("%d %d
",x,y);

    return 0;
}
原文地址:https://www.cnblogs.com/zbtrs/p/7622978.html