题解 SP1553 【BACKUP - Backup Files】
SP1553题解
传送门
题目分析
容易发现,最优解中相邻两个办公楼一定是相邻的,我们求出每相邻两个办公楼之间的距离
这样本题就被转化为了P1484 (不过P1484是一个环这是一条链,而且本题有多组数据)
比如样例就可以被转化为
解题思路
如果 K = 1,那么结果就是
如果 K = 2,那么就有两种情况:
- 选择最小值
a_i ,不选a_{i-1} ,a_{i+1} ,再从剩下的数中选择最小值。 - 不选最小值
a_i ,选a_{i-1} ,a_{i+1} 。
为什么不选最小值
如果只选了
显然
所以最小值左右两侧的数要么都选,要么都不选。
所以我们可以先选上
代码实现思路
所以我们可以建立一个链表 Q,分别记录
每次取出堆顶,更新答案。再删除节点(链表中打标记、更新左右节点数组,小根堆中删除)、插入新节点。
执行
易错点
- 有多组数据,每次记得清空堆和链表
- 记得开 long long
AC代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
void read(int &x){
int f=1;x=0;
char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
x*=f;
}
#define N 100010
priority_queue < pair <ll,int > > q;
int n,k,le[N],r[N],t;
bool v[N];
long long ans,a[N];
void del(int x){
le[r[x]]=le[x];
r[le[x]]=r[x];
v[x]=1;
}
int main(){
read(t);
while(t--){
memset(le,0,sizeof(le));
memset(r,0,sizeof(r));
memset(v,0,sizeof(v));
memset(a,0,sizeof(a));
while(q.size()) q.pop();
ans=0;
read(n),read(k);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
n--;
//le[1]=n,le[n]=n-1,r[1]=2,r[n]=1;
for(int i=1;i<=n;i++){
le[i]=i-1,r[i]=i+1;
a[i]=a[i+1]-a[i];
q.push(make_pair(-a[i],i));
}
a[0]=a[n+1]=1234567890;
while(k--){
int x,y;
while(v[q.top().second]) q.pop();
x=q.top().second;q.pop();
ans+=a[x];
//printf("%lld %d\n",ans,x);
a[x]=a[le[x]]+a[r[x]]-a[x];
v[x]=0;
del(le[x]),del(r[x]);
q.push(make_pair(-a[x],x));
}
cout<<ans<<endl;
}
return 0;
}