您的位置:首页 > 其它

BZOJ 2151 种树 贪心 双向链表优化

2016-10-25 22:21 232 查看
给你一个n个点的环,每个点有点权,在环上取出互不相邻的m个点,求最大值

我们可以贪心,将所有的点扔入一个堆里

每次取出堆顶的元素,然后在双向链表中删去这个点

然而这样可能是错的,比如1354

正确答案应该是7

所以我们要给自己退路

在选择一个元素的时候,将该元素的值改为两边元素的和减去该元素,然后删去两边的元素

然后选择m次

我们来想他的正确性

首先:就算这两个不是最优的,我们下一次不会再选回来,一定可以保证答案的最优性

其次:我们不会选少,每次如果选出一个没选过的,肯定没问题,如果是一个选过的周边,也不会有什么问题,因为我们减去了原来的权值,保证了答案的完备性

其实画画就明白了,我就是没事瞎想的……总之对就是了

时间复杂度mlog(n)

TIPS 我的链表是数组的

所以喜欢指针的大神可以关掉页面了……

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <queue>
#define N 200000+5
using namespace std;

inline int read()
{
int x=0,f=1;char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-')f=-1;ch = getchar();}
while(ch >='0' && ch <='9'){x=(x<<1)+(x<<3)+ch-'0';ch = getchar();}
return x*f;
}

struct data
{
int pos;
int val;
bool operator < (const data &z)const
{
return val < z.val;
}
data () {}
data (int _pos,int _val)
:pos(_pos),val(_val){}
};

priority_queue<data>Q;

int L
,R
,a
;
bool del
;
int ans = 0;

void work()
{
while(del[Q.top().pos])
Q.pop();
data tmp = Q.top();Q.pop();
int tt = tmp.pos;
ans += a[tt];
a[tt] = a[L[tt]] + a[R[tt]] - a[tt];
Q.push(data(tt,a[tt]));
R[L[L[tt]]] = tt;
L[R[R[tt]]] = tt;
del[R[tt]] = del[L[tt]] = 1;
L[tt] = L[L[tt]];
R[tt] = R[R[tt]];
}

int main()
{
int n = read(), m = read();
if(m > (n>>1)){puts("Error!");return 0;}
for(int i=1;i<=n;++i)
{
a[i] = read();
Q.push(data(i,a[i]));
L[i] = i-1;
R[i] = i+1;
}
L[1] = n;
R
= 1;
while(m--)
work();
cout<<ans;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  链表 BZOJ