这题想得脑阔疼。。。我只想到可以选一个点,或者不选这个点选其左右两个点的和
先来特殊情况,k=1, 然后k=2
可以发现由1到2的过程中,可以是一个本来被选的点,替换为他左右两边的点,收益增加了a[pos+1] + a[pos-1] - a[pos]
这个题是一个个选,直到选了k个,有种递推的感觉,先确定种了前面几个,再确定这一个该怎么种
然后我不会处理若有别的点也选上,并且影响到这个pos+1和pos-1的情况
事实上可以把这三个点缩在一起啊(当然不能提前缩,要在pos这个点被选时缩起来)
然后我若再选一个别的点,若这个别的点会影响到pos+1或pos-1,因为缩了点,pos+1和pos-1现在都在pos上,所以这个“别的点”就会让pos的值不可用,由于我们把值也缩在pos上了,直接导致这个pos替换为pos+1和pos-1不可用了,这也符合题意,并且更好写
但是还是有点难处理怎么缩点,缩点之后应当删除3个点,新建一个点,而原来其他位于这三个点左边最靠右的点,若我们选了这个点,这说明这三个点就不可选了,也就是新点不可选,所以要把原来位于左边最靠右的点的右边连到新点上,这就需要开几个数组模拟链表什么的了
堆的题拆点(一个点拆成两个,可以是等大的两个,对左右两边起一个桥梁作用)和缩点(删点)比较多
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 1000000 + 10;
typedef long long ll;
ll n,k,a[MAXN],ans,flg[MAXN],cnt,l[MAXN],r[MAXN];
bool fina;
struct node{
int val, pos;
bool operator < (const node & a) const {
return val < a.val;
}
};
priority_queue<node> q;
int main() {
scanf("%lld%lld", &n, &k);
for(int i=1; i<=n; i++) {
scanf("%lld", &a[i]);
l[i] = i-1;
r[i] = i+1;
q.push((node){a[i], i});
}
int tot = n;
while(!q.empty()) {
node now = q.top();
q.pop();
if(now.val <= 0) break;
int pos = now.pos;
if(flg[pos]) continue;
if(++cnt > k) break;
ans += now.val;
a[++tot] = a[l[pos]] + a[r[pos]] - a[pos];
flg[pos] = flg[r[pos]] = flg[l[pos]] = 1;
l[tot] = l[l[pos]], r[tot] = r[r[pos]];
r[l[tot]] = tot;
l[r[tot]] = tot;
q.push((node){a[tot], tot});
}
printf("%lld", ans);
return 0;
}
原文地址:https://www.cnblogs.com/Zolrk/p/9785086.html
时间: 2024-10-08 20:44:51