题目描述
cyrcyr今天在种树,他在一条直线上挖了n个坑。这n个坑都可以种树,但为了保证每一棵树都有充足的养料,cyrcyr不会在相邻的两个坑中种树。而且由于cyrcyr的树种不够,他至多会种k棵树。假设cyrcyr有某种神能力,能预知自己在某个坑种树的获利会是多少(可能为负),请你帮助他计算出他的最大获利。
输入输出格式
输入格式:
第一行,两个正整数n,k。
第二行,n个正整数,第i个数表示在直线上从左往右数第i个坑种树的获利。
输出格式:
输出1个数,表示cyrcyr种树的最大获利。
输入输出样例
说明
对于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 ",ans); 46 return 0; 47 }