卧薪尝胆,厚积薄发。
CTSC2007 数据备份
Date: Wed Sep 05 08:39:51 CST 2018
In Category:
NoCategory
Description:
在一个数轴上有
$n$
个点,从里面选出
$2k$
个点组成
$k$
组,每组点之间的距离和最小。
$1\le n \le 100000$
Solution:
首先发现每个点只会和他相邻的点连边,于是把位置数组查分,得到
$n-1$
个长度,要求在这
$n-1$
个中选出不相邻的
$k$
个使得他们的和最小,可以像[[bzoj2288]POJ Challenge 生日礼物](http://localhost:4000/2018/09/04/bzoj2288/)一样做,即把所有的丢进一个堆里,每次取堆顶,但是可能会取相邻的两段,如果取了相邻的,一定会同时取两边,即如果序列为
$ABCDEF$
,如果
$C$
最小,但最终答案里有
$D$
,那一定也选了
$B$
,因为
$D$
没有
$C$
优,之所以放弃
$C$
一定是因为放弃它能得到
$B$
,所以每个数取出之后把他的权值设为
$val[pre]+val[nxt]-val[pos]$
放回堆里,再把左右删除即可。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
using namespace std;
int n,m;
#define MAXN 100010
int p[MAXN];
int lef[MAXN],rig[MAXN];
priority_queue< pair<int,int> > q;
#define fi first
#define se second
bool tag[MAXN];
int val[MAXN];
#define INF 0x3f3f3f3f
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;++i)scanf("%d",&p[i]);
int ans = 0;
for(int i = 1;i < n;++i)
{
lef[i] = i - 1,rig[i] = i + 1;
tag[i] = false;
val[i] = p[i + 1] - p[i];
q.push(make_pair(-val[i],i));
}
val[0] = val[n] = INF;
rig[0] = 1;lef[n] = n - 1;
--n;
for(int i = 1;i <= m;)
{
pair<int,int> k = q.top();q.pop();
if(tag[k.se])continue;
ans += val[k.se];
++i;
tag[lef[k.se]] = tag[rig[k.se]] = true;
val[k.se] = val[lef[k.se]] + val[rig[k.se]] - val[k.se];
rig[lef[lef[k.se]]] = lef[rig[rig[k.se]]] = k.se;
lef[k.se] = lef[lef[k.se]];rig[k.se] = rig[rig[k.se]];
q.push(make_pair(-val[k.se],k.se));
}
cout << ans << endl;
return 0;
}
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡