BZOJ1588 [HNOI2002]营业额统计

题意

营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况。 Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额。分析营业情况是一项相当复杂的工作。由于节假日,大减价或者是其他情况的时候,营业额会出现一定的波动,当然一定的波动是能够接受的,但是在某些时候营业额突变得很高或是很低,这就证明公司此时的经营状况出现了问题。经济管理学上定义了一种最小波动值来衡量这种情况: 该天的最小波动值 当最小波动值越大时,就说明营业情况越不稳定。 而分析整个公司的从成立到现在营业情况是否稳定,只需要把每一天的最小波动值加起来就可以了。你的任务就是编写一个程序帮助Tiger来计算这一个值。 第一天的最小波动值为第一天的营业额。 

简述:给出一个序列,对于每一个数,找出之前与它相差最小的数,两者相减取绝对值加入答案。

\(n<=32767\)

分析

参照wolf940509的题解。

首先,将这\(N\)个元素进行排序,同时记录下原来第\(i\)个元素在排序后的位置\(b_i\). 接着,将排序后的序列建成一个双向链表。然后,按照从\(a_n\)\(a_1\)的顺序依次处理每个元素。对于\(a_n\),由于知道它在排序后的序列中的位置\(b_n\),可以查看\(b_n\)的前驱\(pre[b_n]\)与后继\(next[b_n]\)所指的数。很显然,由于数据在双向链表中是有序的,所以最小波动值必然是\(a_n\)与这两个数中的某一个的差的绝对值。当然,如果前驱或后继为空,就不需要考虑相应的位置了。处理完\(a_n\)后,我们把它从双向链表中删除(由前文可知,这一步操作的时间复杂度仅为\(O(1)\)),接着处理\(a_{n-1}\). 这样,每当处理\(ai\)时,\(a_{i+1},a_{i+2},……, a_n\)已被从双向链表中删除,而此时\(b_i\)的前驱与后继所指的数就等于将\(a_1,a_2,……, a_i\)排序后\(a_i\)的前驱与后继。整个算法分为排序,建表与处理三部分。很显然,建表与处理的时间复杂度均为\(O(N)\),所以此算法的时间复杂度与排序的时间复杂度同阶,为\(O(N \log_2 N)\).

第一次做到双向链表的题。这个思路真的妙。

代码

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read()
{
    rg T data=0;
    rg int w=1;
    rg char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            w=-1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        data=data*10+ch-'0';
        ch=getchar();
    }
    return data*w;
}
template<class T>il T read(rg T&x)
{
    return x=read<T>();
}
using namespace std;
typedef long long ll;

co int N=32768;

struct Node
{
    int num,pos;
    int L,R;
    
    bool operator<(co Node&rhs)co
    {
        return num<rhs.num;
    }
}p[N];
int b[N],c[N];

int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
    int n;
    read(n);
    for(int i=1;i<=n;++i)
    {
        read(p[i].num);
        c[i]=p[i].num;
        p[i].pos=i;
    }
    sort(p+1,p+n+1);
    for(int i=1;i<=n;++i)
        b[p[i].pos]=i;
    for(int i=1;i<=n;++i)
    {
        p[i].L=i-1;
        p[i].R=i+1;
    }
    p[n].R=0;
    int ans=c[1];
    for(int i=n;i>1;--i)
    {
        int x=b[i];
        if(p[x].L&&p[x].R)
        {
            ans+=min(p[x].num-p[p[x].L].num,p[p[x].R].num-p[x].num);
            p[p[x].L].R=p[x].R;
            p[p[x].R].L=p[x].L;
        }
        else if(!p[x].L)
        {
            ans+=p[p[x].R].num-p[x].num;
            p[p[x].R].L=0;
        }
        else
        {
            ans+=p[x].num-p[p[x].L].num;
            p[p[x].L].R=0;
        }
    }
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/autoint/p/10311100.html