对于一个给定的序列a1, …, an,我们对它进行一个操作reduce(i),该操作将数列中的元素ai和ai+1用一个元素max(ai,ai+1)替代,这样得到一个比原来序列短的新序列。这一操作的代价是max(ai,ai+1)。进行n-1次该操作后,可以得到一个长度为1的序列。
我们的任务是计算代价最小的reduce操作步骤,将给定的序列变成长度为1的序列。
容易发现一个贪心思路:
每次选最小的数和它两边的数中较小的那个数合并。
可以将所有的数排序之后用链表O(1)维护。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
struct qnode {
int w;
int p;
bool operator < (const qnode &r) const {
return w>r.w;
}
};
priority_queue<qnode> q;
int a[maxn];
int nxt[maxn],pre[maxn];
int p[maxn];
int n;
int b[maxn];
int cmp (int x,int y) {
return a[x]<a[y];
}
int main () {
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",a+i);
for (int i=1;i<=n;i++) {
if (i<n) nxt[i]=i+1;
if (i>1) pre[i]=i-1;
b[i]=i;
}
sort(b+1,b+n+1,cmp);
long long ans=0;
for (int i=1;i<=n;i++) {
int p=b[i];
if (pre[p]&&nxt[p]) {
if (a[pre[p]]<a[nxt[p]]) {
ans+=a[pre[p]];
}
else {
ans+=a[nxt[p]];
}
nxt[pre[p]]=nxt[p];
pre[nxt[p]]=pre[p];
}
else if (pre[p]) {
ans+=a[pre[p]];
nxt[pre[p]]=nxt[p];
}
else if (nxt[p]) {
ans+=a[nxt[p]];
pre[nxt[p]]=pre[p];
}
}
printf("%lld
",ans);
}