JZOJ #4726 种花 (带恢复操作的堆)

题目描述:

在圆周上有$N$个点,每个点有不同的贡献,要求选$M$个点,不能相邻,问最大的贡献。

解题思路:

将所有点扔进一个按贡献的大根堆里,取$M$次,每次取出堆顶$k$。答案加$V_k$,设$k$的前继为$lst$,后继$nxt$,令$V_k=V_{lst}+V_{nxt}-V_k$,再扔进堆里。并令$k$的前继为前继的前继,后继类似。为什么这样呢,新的$k$表示不选$k$这个位置,而取$k$的前继和后继,而这样取的次数不会多或少。那为什么一定是取前继和后继,严格证明我也不会。但手玩一下确实是这样。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <queue>
 5 using namespace std;
 6 
 7 const int N = 2e5 + 10;
 8 int n, m, a[N], lst[N], nxt[N], ans, mov[N];
 9 
10 struct node {int k;};
11 bool operator < (node x, node y) {return a[x.k] < a[y.k];}
12 priority_queue <node> h;
13 
14 int main() {
15     scanf("%d %d", &n, &m);
16     if (n < m * 2) {
17         printf("Error!");
18         return 0;
19     }
20     for (int i = 1; i <= n; i ++) scanf("%d", &a[i]), h.push((node) {i});
21     for (int i = 1; i < n; i ++) nxt[i] = i + 1; nxt[n] = 1;
22     for (int i = 2; i <= n; i ++) lst[i] = i - 1; lst[1] = n;
23     while (m --) {
24         node now = h.top(); h.pop();
25         while (mov[now.k]) {
26             now = h.top();
27             h.pop();
28         }
29         ans += a[now.k];
30         a[now.k] = a[lst[now.k]] + a[nxt[now.k]] - a[now.k];
31         mov[lst[now.k]] = 1;
32         mov[nxt[now.k]] = 1;
33         lst[now.k] = lst[lst[now.k]], nxt[lst[now.k]] = now.k;
34         nxt[now.k] = nxt[nxt[now.k]], lst[nxt[now.k]] = now.k;
35         h.push((node) {now.k});
36     }
37     printf("%d", ans);
38     return 0;
39 }

 

转载于:https://www.cnblogs.com/awner/p/5797034.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值