洛谷 P2234 [HNOI2002]营业额统计

---恢复内容开始---

我看到很多人都是用treap或者是splay来做的,但是本蒟蒻还没有完全理解,所以本来就只想打暴力骗个分,但是没想到骗着骗着就骗到了100分  

题目描述:

Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况。

Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额。分析营业情况是一项相当复杂的工作。由于节假日,大减价或者是其他情况的时候,营业额会出现一定的波动,当然一定的波动是能够接受的,但是在某些时候营业额突变得很高或是很低,这就证明公司此时的经营状况出现了问题。经济管理学上定义了一种最小波动值来衡量这种情况:

当最小波动值越大时,就说明营业情况越不稳定。

而分析整个公司的从成立到现在营业情况是否稳定,只需要把每一天的最小波动值加起来就可以了。你的任务就是编写一个程序帮助Tiger来计算这一个值。

第一天的最小波动值为第一天的营业额。

该天的最小波动值=min{|该天以前某一天的营业额-该天营业额|}。

输入/输出格式:

第一行为正整数n(n<=32767) ,表示该公司从成立一直到现在的天数,接下来的n行每行有一个整数ai(|ai|<=1000000) ,表示第i天公司的营业额,可能存在负数。

输出文件仅一个数,每一天的最小波动值总和,结果小于2^31

样例:

in:                                                                                        out:

6                                                    12     
5
1
2
5
4
6

大致思路
题中所知,每一个数的大小不超过一百万,很明显可以用数组存下来,不过要注意的是:数组的下标不能为负数
所以要用两个数组分别储存正数,负数,这里我用res1为正数,res2为负数
再将每一个数一个一个枚举,在每次寻找中间,从这个数本身开始,每次-1和+1,如果找到一个数是已经标记过了的,那么这个这两个数的差肯定是该天最小波动值,需要注意的是,每次枚举时,要在最后标记
当然,还有一点需要注意:可能会有以前的数和现在的是相等的,所以自身也是要看看有没有标记过
最后一点,卡了我一个下午:如果要判断这个数有没有被标记过,首先要加绝对值,其次要判断这个数是正数还是负数,才能对应res1或res2
(开long long!!!)

#include<bits/stdc++.h>
using namespace std;

const int N=10000010;
long long number,num[N],Min_prise[N],res1[N],res2[N],ans=0;

long long read(){
    long long s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
    return s*w;
}

int main(){
    number=read();
    for(long long i=1;i<=number;i++)num[i]=read();
    if(num[1]<0)res2[-num[1]]=1;
    if(num[1]>=0)res1[num[1]]=1;
    ans=Min_prise[1]=num[1];
    for(long long i=2;i<=number;i++){
        if(res2[abs(num[i])]&&num[i]<0)continue;
        if(res1[abs(num[i])]&&num[i]>=0)continue;
        for(long long j=1;;j++){
            long long l=(num[i]-j),r=(num[i]+j);
            if((res2[abs(l)]&&l<0)||(res2[abs(r)]&&r<0)){Min_prise[i]=j;break;}
            if((res1[abs(l)]&&l>=0)||(res1[abs(r)]&&r>=0)){Min_prise[i]=j;break;}
        }
        if(num[i]<0)res2[-num[i]]=1;
        if(num[i]>=0)res1[num[i]]=1;
        ans+=Min_prise[i];
    }
    cout<<ans;
    return 0;
}





---恢复内容结束---

原文地址:https://www.cnblogs.com/GMSD/p/11217644.html