前缀和?or差分序列?

前缀和数组是十分基本和简单的一种工具,但是要想真正用好,却不容易。在平时的训练中有很多的问题都要用到前缀和。我们通过一个小的例子来看一下

cogs1190最大和

题目大意:N个数围成一圈,要求从中选择若干个连续的数(注意每个数最多只能选一次)加起来,问能形成的最大的和。

思路:一看到这个题,竟然想到了线段树,后来发现有点大材小用,要是深究的话也不是很会写,于是就另辟蹊径。这个题目中有一个神奇的关系就是这是个环,于是我们就有了两种情况:1)这一段数本身就在给定区间内;2)这一段数被分放在给定区间的两端。第一种情况比较好处理,只用前缀和,跟新最小值和最大的差就可以了;后一种情况就要用到后缀和,找到最大值和后缀和的和取最大。输出最大值就可以了。

#include<iostream>
#include<cstdio>
using namespace std;
int sum1[100001]={0},sum2[100001]={0},a[100001]={0};
int main()
{
    freopen("maxsum.in","r",stdin);
    freopen("maxsum.out","w",stdout);
    
    int n,i,j,maxn,minn;
    maxn=-2100000000;
    scanf("%d",&n);
    for (i=1;i<=n;++i)
    {
        scanf("%d",&a[i]);
        sum1[i]=sum1[i-1]+a[i];
    }
    for (i=n;i>=1;--i)
        sum2[i]=sum2[i+1]+a[i];
    minn=2100000000;
    for (i=1;i<=n;++i)
    {
        if (sum1[i]-minn>maxn) maxn=sum1[i]-minn;
        if (sum1[i]<minn) minn=sum1[i];    
    }
    minn=-2100000000;
    for (i=1;i<=n;++i)
    {
        if (minn+sum2[i]>maxn) maxn=minn+sum2[i];
        if (sum1[i]>minn) minn=sum1[i];
    }
    printf("%d
",maxn);
    
    fclose(stdin);
    fclose(stdout);
}
View Code

这样一道题目中展现了前缀和的特殊魅力,以后还要多加练习,熟练应用。

现在才知道,这个二级前缀和数组好像是一种高端的东西,差分序列。

cogs1435金发姑娘和N头牛

题目大意:取一种温度,让牛能产出最多的奶。已知每头牛最适合的温度和在这个温度区间上中下不同的产奶量。

思路:先离散化,然后扫一遍所有的ai、bi,然后在0、ai、bi+1(一开始写成了bi,竟然过了75分。。。)处加上相应的值、在ai、bi+1、maxn减去相应的值,最后从头到尾扫一遍前缀和数组,最大值就是答案了。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int a[20001]={0},b[20001]={0},cc[80001]={0},sum[100000]={0},dd[100000]={0};
int main()
{
    freopen("milktemp.in","r",stdin);
    freopen("milktemp.out","w",stdout);
    
    int maxn=0,n,i,j,x,y,z,tot=0,size,ans=0;
    scanf("%d%d%d%d",&n,&x,&y,&z);
    for (i=1;i<=n;++i)
    {
        scanf("%d%d",&a[i],&b[i]);
        ++tot;cc[tot]=a[i];
        ++tot;cc[tot]=b[i];
    }
    sort(cc+1,cc+tot+1);
    size=unique(cc+1,cc+tot+1)-cc-1;
    for (i=1;i<=n;++i)
    {
        a[i]=upper_bound(cc+1,cc+size+1,a[i])-cc-1;
        b[i]=upper_bound(cc+1,cc+size+1,b[i])-cc-1;
        maxn=max(maxn,max(a[i],b[i]));
    }
    maxn+=2;
    for (i=1;i<=n;++i)
    {
        dd[0]+=x;
        dd[a[i]]-=x;dd[a[i]]+=y;
        dd[b[i]+1]-=y;dd[b[i]+1]+=z;
        dd[maxn]-=z;
    }
    ans=sum[0]=dd[0];
    for (i=1;i<=maxn;++i)
    {
        sum[i]=sum[i-1]+dd[i];
        ans=max(ans,sum[i]);
    }
    printf("%d
",ans);
    
    fclose(stdin);
    fclose(stdout);
}
View Code
原文地址:https://www.cnblogs.com/Rivendell/p/4141406.html