洛谷 P1484 种树

  

题目描述

cyrcyr今天在种树,他在一条直线上挖了n个坑。这n个坑都可以种树,但为了保证每一棵树都有充足的养料,cyrcyr不会在相邻的两个坑中种树。而且由于cyrcyr的树种不够,他至多会种k棵树。假设cyrcyr有某种神能力,能预知自己在某个坑种树的获利会是多少(可能为负),请你帮助他计算出他的最大获利。

输入输出格式

输入格式:

第一行,两个正整数n,k。

第二行,n个正整数,第i个数表示在直线上从左往右数第i个坑种树的获利。

输出格式:

输出1个数,表示cyrcyr种树的最大获利。

输入输出样例

输入样例#1: 复制
6 3 
100 1 -1 100 1 -1
输出样例#1: 复制
200

说明

对于20%的数据,n<=20。

对于50%的数据,n<=6000。

对于100%的数据,n<=500000,k<=n/2,在一个地方种树获利的绝对值在1000000以内。

好像是堆的固定套路,首先肯定是每次取最大的正数,但是可能有差错,如70,100,80,如果只取两个,显然是150。

这时就需要撤回操作,即每弹出一个数时,将一个值为左右两边数的值减去本身加入堆,如果这个被选,就相当于撤回,选了旁边的两个数。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<queue>
 4 using namespace std;
 5 const int N=500005;
 6 int n,k,l[N],r[N];
 7 long long ans;
 8 bool inq[N];
 9 struct node
10 {
11     int id;
12     long long v;
13     bool operator <(node c)const
14     {
15         return v<c.v;
16     }
17 }a[N],t;
18 priority_queue<node>q;
19 int main()
20 {
21     scanf("%d%d",&n,&k);
22     for(int i=1;i<=n;i++)
23     {
24         scanf("%lld",&a[i].v);
25         a[i].id=i;
26         q.push(a[i]);
27         l[i]=i-1;
28         r[i]=i+1;
29     }
30     while(k--)
31     {
32         while(inq[q.top().id])
33             q.pop();
34         if(q.top().v<=0)
35             break;
36         t=q.top();
37         q.pop();
38         ans+=t.v;
39         inq[l[t.id]]=inq[r[t.id]]=1;
40         a[t.id].v=t.v=a[l[t.id]].v+a[r[t.id]].v-t.v;
41         l[t.id]=l[l[t.id]],r[t.id]=r[r[t.id]];
42         r[l[t.id]]=t.id,l[r[t.id]]=t.id;
43         q.push(t);
44     }
45     printf("%lld\n",ans);
46     return 0;
47 }

猜你喜欢

转载自www.cnblogs.com/rlt1296/p/9342761.html
今日推荐