zoukankan      html  css  js  c++  java
  • 前缀和?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
  • 相关阅读:
    Access小用之感
    PHP学习之路今日开启
    IBatis初体验2
    PHP之PDO介绍
    javascript key code 大全
    如何将虚拟机中的Linux系统与shell终端连接
    linux磁盘情况查询
    vi和vim编辑器的使用
    Linux磁盘分区,挂载
    (转)Android Dalvik虚拟机初识
  • 原文地址:https://www.cnblogs.com/Rivendell/p/4141406.html
Copyright © 2011-2022 走看看