题目大意:对给出的距离差分后的n-1个权值中挑出k个不相邻的权值,求挑出的权值的和的最小值。(看懂题目还是挺重要的)
没思路啊没思路,就算告诉我这是一道贪心题我也没思路啊,总不能是堆加链表的骚操作吧……(雾)
对于差分后的n-1个权值,我们可以全都插到堆里。先贪心的挑出一个最小值a,假设这个最小值是答案的一部分,那么显然我们不能单独再取它左边的权值b或右边的权值c了。
那么我们把它左边和右边的权值合成一个权值为b+c-a的权值,插入堆中,显然如果取了这个合成后的权值,就相当于是去了b和c的权值和。
这么搞k次就可以出答案了啊。
p.s.这题的链表需要考虑的细节比较多,望各位大佬细心些。
附上AC代码:
#include <cstdio>
#include <cctype>
#include <queue>
#define INF 0x3f3f3f3f
#define ll long long
#define pr pair<ll,int>
using namespace std;
const int N=100010;
ll n,m,x,len[N],pre,l[N],r[N],ans;
priority_queue <pr,vector<pr>,greater<pr> > que;
inline char nc(void){
static char ch[100010],*p1=ch,*p2=ch;
return p1==p2&&(p2=(p1=ch)+fread(ch,1,100010,stdin),p1==p2)?EOF:*p1++;
}
inline void read(ll &a){
static char c=nc();int f=1;
for (;!isdigit(c);c=nc()) if (c=='-') f=-1;
for (a=0;isdigit(c);a=(a<<3)+(a<<1)+c-'0',c=nc());
a*=f;return;
}
int main(void){
read(n),read(m),pre=0;
for (int i=1; i<=n; ++i) read(x),len[i]=x-pre,pre=x,l[i]=i-1,r[i]=i+1;
for (int i=2; i<=n; ++i) que.push(make_pair(len[i],i));
l[2]=0,r[n]=0;
while (m--){
while (que.top().first!=len[que.top().second]) que.pop();
int p=que.top().second,x=l[p],y=r[p];
ans+=len[p],que.pop();
l[r[p]=r[y]]=p,r[l[p]=l[x]]=p;
len[p]=x&&y?len[x]+len[y]-len[p]:INF;
len[x]=len[y]=INF;
que.push(make_pair(len[p],p));
}
printf("%lld\n",ans);
return 0;
}