ACWing 147.資料備份

LeBronGod發表於2020-10-06

在這裡插入圖片描述

題意:

選取K對大樓,使得每對距離之和最小,並且一個大樓只會被連結一次

思路:

當k=1時肯定就是貪心的選取距離最小的那兩棟。
當k=2時我們是否還要留著距離最小的那一對呢?如果沒有選擇距離最小的那一對,那肯定要選擇最小那一對的左右兩對,否則就可以將其中一對換成最小的那對,那樣會更小。
當k>2時同理如果不選擇中間的就必須選擇其左右兩邊的,這樣才能保證較小的那對我是因為實在拿不了的才放棄的,否則就可以更優。
我們可以用一個雙指標連結串列加一個set來完成這些工作,當刪去中間這對時將其左右兩對的權值重新加入set模擬最優策略的過程;

AC程式碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
typedef pair<ll,int> PLI;
set<PLI> s;
int l[maxn],r[maxn];
ll d[maxn];
int n,k;
void delete_node(int p) {
	r[l[p]] = r[p];
	l[r[p]] = l[p];
}
int main()
{
	cin>>n>>k;
	for(int i=0;i<n;i++) {
		cin>>d[i];
	}
	for(int i=n-1;~i;i--) {
		d[i] -= d[i-1];
	}
	d[0] = d[n] = 1e15;
	for(int i=0;i<n;i++) {
		l[i] = i-1;
		r[i] = i+1;
		if(i>=1&&i<n) s.insert({d[i],i});
	}
	ll res = 0;
	while(k--) {
		auto it = s.begin();
		ll v = it->first;
		int p = it->second;
		int left = l[p],right = r[p];
		s.erase(it);
		s.erase({d[left],left});s.erase({d[right],right});
		delete_node(left),delete_node(right);
		res+=v;
		
		d[p] = d[left]+d[right]-d[p];
		s.insert({d[p],p});
	}
	cout<<res<<endl;
}

相關文章