Codeforces 1197D Yet Another Subarray Problem(前缀和+暴力统计)

题目链接:http://codeforces.com/problemset/problem/1197/D

题目大意:给出一列数组和两个常数m,k,然后定义一段子序列的cost等于该段子序列各元素之和减去该段长度与m之商的向上取整的值与k的乘积。求任取一段连续子序列所能得到的最大的cost。(ps:可以取空集,此时子序列的cost为0)

思路:因为涉及到区间和的操作,就可以使用前缀和预处理,把On的查询简化为O1。由题目那条特别注释可以得到最终答案必定大于等于0,因为当取非空集得到的cost都小于0时我们可以取一个空集的cost也就是0作为最大值,所以就不必在初始化的时候把某些数组初始化为-inf这样麻烦的数字。

然后,cost的计算式中的(r-l+1)/m的向上取整近似于对该子序列进行分块,未满m的一律按一块计算。因此我们可以以小于等于m为一块来统计某个点以前(包含)的最大值,而题目数据量并不大,我们可以直接暴力统计。

#include
#include
#include<set>
#include
#include<string.h>
#include
#include
#include
#include
#include
#include
#include
using namespace std;
long long a[300005];
long long f[300005];
int n,m,k;
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%I64d",&a[i]);
        a[i]+=a[i-1];
    }
    long long ans=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=i;j>=1&&j>=i-m+1;j--)
        {
            f[i]=max(a[i]-a[j-1]-k,f[i]);
        }
        if(i-m>0)
        {
            f[i]=max(a[i]-a[i-m]+f[i-m]-k,f[i]);//如果前面的点i-m有定义并且加上它的值更大的话(也就是两段可以连起来得到更大的cost),将两段的值合并到后一段上继续统计
        }
        ans=max(ans,f[i]);
    }
    printf("%I64d\n",ans);
    return 0;
}

 

转载于:https://www.cnblogs.com/forever3329/p/11231679.html

你可能感兴趣的:(Codeforces 1197D Yet Another Subarray Problem(前缀和+暴力统计))