【题意】
给出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;
}