P4393 [BOI2007]Sequence 序列問題(連結串列)
阿新 • • 發佈:2021-07-21
對於一個給定的序列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\n",ans); }