前缀和?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\n",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\n",ans);

    

    fclose(stdin);

    fclose(stdout);

}
View Code

 

你可能感兴趣的:(序列)