【链表】营业额统计

【题意】
给出n个数,每个数都有一个波动值,是对于前面每个数的差的绝对值的最小值。第一个数的波动值就是其本身。求n个数的最小波动值之和。
n<=32767
【思路】
将元素排序后做成链表,用to[i]表示i在排序后的位置。从最后一天开始计算,找到它在链表中的位置,其值为xVal,其链表左边的值为lVal,其链表右边的值为rVal,由于排序过所以一定满足lVal小于xVal小于rVal,其波动值为min( abs(xVal-lVal) , abs(xVal-rVal) )。因为它是原序列最后一个元素,所以链表上所有其它元素都在原序列的它的前面,可以与它计算波动值。
那么我们计算倒数第二个元素的时候,就不能与最后一个元素计算波动值了,所以计算完一个元素的波动值后,将其从链表中删去,这样每次计算一个元素时,链表内其他元素都是可以与其计算波动值的(虽然实际上有用的只是它的两边两个元素)。
【代码】

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 51000
#define inf 999999999
using namespace std;
inline int read()
{
    int ans=0,f=1;
    char x=getchar();
    while(x<'0'||x>'9')
    {
        if(x=='-')f=-1;
        x=getchar();
    }
    while(x>='0'&&x<='9')
    {
        ans=ans*10+x-'0';
        x=getchar();
    }
    return ans*f;
}
struct node
{
    int val,loc;
    node()
    {
        val=inf;
    }
}a[MAXN];
bool cmp(node x,node y)
{
    return x.val<y.val;
}
int n,ans=0,to[MAXN],pre[MAXN],nex[MAXN];
void del(int x)
{
    int l=pre[x],r=nex[x];
    nex[l]=r;
    pre[r]=l;
    nex[x]=pre[x]=0;
    return ;
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
    {
        a[i].val=read();
        a[i].loc=i;
    }
    sort(a+1,a+1+n,cmp);
    for(int i=1;i<=n;i++)
    {
        pre[i]=i-1;
        nex[i-1]=i;
        to[a[i].loc]=i;
    }
    for(int i=n;i>=1;i--)
    {
        int x=to[i];
        if(i==1)
        {
            ans+=a[to[1]].val;
            break;
        }
        ans+=min( abs(a[x].val-a[nex[x]].val) , abs(a[x].val-a[pre[x]].val) );
        del(x);
    }
    printf("%d\n",ans);
    return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值