列表

详情


NC50997. 数据备份

描述

你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份。然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的乐趣。已知办公楼都位于同一条街上。你决定给这些办公楼配对(两个一组)。每一对办公楼可以通过在这两个建筑物之间铺设网络电缆使得它们可以互相备份。然而,网络电缆的费用很高。当地电信公司仅能为你提供 K 条网络电缆,这意味着你仅能为 K 对办公楼(或总计2K个办公楼)安排备份。任一个办公楼都属于唯一的配对组(换句话说,这 2K 个办公楼一定是相异的)。此外,电信公司需按网络电缆的长度(公里数)收费。因而,你需要选择这 K 对办公楼使得电缆的总长度尽可能短。换句话说,你需要选择这 K 对办公楼,使得每一对办公楼之间的距离之和(总距离)尽可能小。下面给出一个示例,假定你有 5 个客户,其办公楼都在一条街上,如下图所示。这 5 个办公楼分别位于距离大街起点 1km, 3km, 4km, 6km 和 12km 处。电信公司仅为你提供 K=2 条电缆。
上例中最好的配对方案是将第 1 个和第 2 个办公楼相连,第 3 个和第 4 个办公楼相连。这样可按要求使用K=2 条电缆。第 1 条电缆的长度是 3km-1km=2km ,第 2 条电缆的长度是 6km-4km=2km。这种配对方案需要总长4km 的网络电缆,满足距离之和最小的要求。

输入描述

第一行包含整数n和k
其中n表示办公楼的数目,k表示可利用的网络电缆的数目。
接下来的n行每行仅包含一个整数,表示每个办公楼到大街起点处的距离。
这些整数将按照从小到大的顺序依次出现。

输出描述

输出应由一个正整数组成,给出将2K个相异的办公楼连成k对所需的网络电缆的最小总长度。

示例1

输入:

5 2 
1
3
4
6
12

输出:

4

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 199ms, 内存消耗: 9188K, 提交时间: 2020-06-06 22:55:37

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
typedef long long ll;
typedef pair<ll,int>pii;
int n,k,l[N],r[N];
ll d[N];
void delete_d(int p)
{
	int left=l[p],right=r[p];
	l[right]=left;
	r[left]=right;
}
int main()
{
	scanf("%d%d",&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;
	set<pii>q;
	for(int i=0;i<=n;i++)
	{
		l[i]=i-1;
		r[i]=i+1;
		if(i>=1&&i<n)q.insert({d[i],i});
	}
	ll res=0;
	while(k--)
	{
		auto it=q.begin();
		ll a=it->first;
		int p=it->second,left=l[p],right=r[p];
		q.erase(it);
		q.erase({d[left],left});
		q.erase({d[right],right});
	    delete_d(left);
	    delete_d(right);
	    d[p]=d[left]+d[right]-d[p];
	    q.insert({d[p],p});
	    res+=a;
	}
	cout<<res<<endl;
    return 0;
}

C++ 解法, 执行用时: 96ms, 内存消耗: 6264K, 提交时间: 2021-09-13 09:53:23

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,k,a[N],pre[N],nxt[N],ans; 
struct node{
	int val,id;
	friend bool operator<(node x,node y){
		return x.val==y.val?x.id<y.id:x.val<y.val;
	} 
};
set<node>s;
void del(int x){
	nxt[pre[x]]=nxt[x],pre[nxt[x]]=pre[x];
}
signed main(){
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),pre[i]=i-1,nxt[i]=i+1;
	for(int i=1;i<n;i++) a[i]=a[i+1]-a[i],s.insert((node){a[i],i});
	a[0]=a[n]=1e9;
	for(int i=1;i<=k;i++){
		node x=*s.begin();
		int p=x.id,l=pre[p],r=nxt[p];
		ans+=x.val,del(l),del(r);
		s.erase((node){a[l],l}),s.erase((node){a[r],r}),s.erase(x);
		a[p]=a[l]+a[r]-a[p],s.insert((node){a[p],p});
	}
	printf("%d\n",ans);
	return 0;
}

C++(g++ 7.5.0) 解法, 执行用时: 56ms, 内存消耗: 4500K, 提交时间: 2023-07-28 20:39:26

#include<bits/stdc++.h>
using namespace std;
long long n,k,ans,a[1000001],pre[1000001],nxt[1000001],del[1000001];
struct cmp{
	inline long long operator()(long long x,long long y){return a[x]>a[y];}
};
priority_queue<long long,vector<long long>,cmp>q;
int main(){
	scanf("%lld%lld%lld",&n,&k,&a[1]);
	for(register int i=2;i<=n;++i)scanf("%lld",&a[i]),a[i-1]=a[i]-a[i-1];
	--n;a[0]=1e18;
	for(register int i=1;i<=n;++i)q.push(i),pre[i]=i-1,nxt[i]=i+1>n?0:i+1;
	while(k--){
		long long x=q.top();q.pop();
		while(del[x])x=q.top(),q.pop();
		ans+=a[x];del[pre[x]]=del[nxt[x]]=1,a[x]=a[pre[x]]+a[nxt[x]]-a[x];q.push(x);pre[x]=pre[pre[x]];nxt[x]=nxt[nxt[x]];nxt[pre[x]]=x;pre[nxt[x]]=x;
	}
	printf("%lld",ans);
} 

上一题