您的位置:首页 > 其它

[codevs1615]数据备份

2017-10-17 18:42 148 查看
题目←

大意:

可以转换成n条线段中选k条端点不重合的线段,要求线段之和最小

发现一条线段选了之后会影响两边的,考虑链表

还有这样一条替代关系:

选择一条长度为v的线段后,两旁的线段不能再选,但若要重选两条线段,可将答案增加lv+rv-v来抵消

其中lv、rv为左右线段的价值

综上,选择一条价值为v的线段时,在链表空间中新加入lv+rv-v,代替v的位置

然后继续从小到大贪心就可以了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#define LL long long
#define INF 1061109567
using namespace std;
const int MAXN = 1000000 + 50;
LL next[MAXN],pre[MAXN],A[MAXN],D[MAXN];
struct zt{
LL pos;
LL cost,v;
}l[MAXN];
bool operator < (zt a,zt b){
return a.v > b.v;
}
priority_queue <zt> q;
LL n,m,k,cnt;
int first;
LL tot,ans,now;
bool del[MAXN];
int main()
{
scanf("%lld%lld",&n,&m);
scanf("%lld",&D[1]);
for(int i = 2;i <= n;i ++){
scanf("%lld",&D[i]);
A[++ cnt] = D[i] - D[i - 1];
}
for(int i = 1;i <= cnt;i ++){
pre[i] = i - 1;
next[i - 1] = i;
q.push((zt){i,1,A[i]});
}
pre[0] = -1;
next[cnt] = cnt + 1;
first = 0;
A[0] = INF;
A[cnt + 1] = INF;
cnt ++;
while(!q.empty())
{
zt u = q.top();
q.pop();
if(del[u.pos])continue;
tot += u.cost;
now += u.v;
if(tot == m){
ans = now;
break;
}
u.v = -u.v;
u.v += A[pre[u.pos]] + A[next[u.pos]];
A[++ cnt] = u.v;
int tmp1 = pre[u.pos],tmp2 = next[u.pos];
next[pre[tmp1]] = cnt;
pre[next[tmp2]] = cnt;
pre[cnt] = pre[tmp1];
next[cnt] = next[tmp2];
del[tmp1] = del[tmp2] = del[u.pos] = true;
u.pos = cnt;
q.push(u);
}
printf("%lld",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: