前缀和例题

首先我们要注意到:序列是非递减序列,由此我们可以得到一个消息:当一个数往前挪的时候,挪k个一定比挪k+1个要优。然后:挪最后一个未必是最优的,从样例就可以看出来。这样我们就需要枚举挪哪一个。如果每次枚举然后求和的话复杂度是n^2的,所以说前缀和真是个好东西。假如把第x个数向前挪k个,那么从x往后和x-k往前的数,他们对数列的贡献是不变的,因为他们的位置没有变。所以我们可以先预处理出来初始序列的优美值,然后,[x-k,x-1]这k个数整体向后挪了一个,每个人的贡献值都是比之前多了一个本身,我们处理处不加权的前缀和加一个这段的值就可以了,最后是第x个数,他的值a[x]*k,这样每次o(1)算出序列的优美度,枚举下来就是o(n)的。

#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
const int maxn=1e5+5;
ll ans;
int t;
int n,k;
ll a[maxn];
ll s[maxn],ss[maxn];
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;++i)
            scanf("%d",&a[i]),s[i]=s[i-1]+i*a[i],
            ss[i]=ss[i-1]+a[i];
        ans=0;
        for(int i=k+1;i<=n;++i)
            ans=max(ans,s[n]-i*a[i]+(i-k)*a[i]+ss[i-1]-ss[i-k-1]);
        cout<<ans<<endl;
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/yuelian/p/12682052.html