1. 程式人生 > 其它 >P4393 [BOI2007]Sequence 序列問題(連結串列)

P4393 [BOI2007]Sequence 序列問題(連結串列)

對於一個給定的序列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);
}