luogu1484 种树

题目大意:

给定一个大小为n的序列$ a_1,a_2,a_3...a_n $,问从中选至多k个不相邻的数(可以小于k个),权值和最大为多少。

解题方法:

考虑选取一个数对其两边的影响,当选了$ a_p $时,p位置左侧的数和右侧的数都无法选,但存在一种决策,即放弃$ a_p $,选择$ a_pl $和$ a_pr $,为实现这一操作,可用链表,每次选出$ a_p $后,将 $ a_pl+a_pr-a_p $ 填在p位置并更新左右指针,每次从中选最大的数,用堆维护即可。

代码:

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 #define del(a,b) memset(a,b,sizeof(a))
 4 using namespace std;
 5 const int MAXN=5e5+10;
 6 int n,k;
 7 bool vis[MAXN];
 8 ll a[MAXN],l[MAXN],r[MAXN];
 9 struct Node
10 {
11     ll val;int id;
12     Node(ll a,int b):val(a),id(b){}
13     friend bool operator <(const Node &a,const Node &b){return a.val<b.val;}
14 };
15 priority_queue<Node> Q;
16 template <class T>void read(T &x)
17 {
18     bool f=0;char ch=getchar();x=0;
19     for(;ch<'0' || ch>'9';ch=getchar())if(ch=='-') f=1;
20     for(;ch>='0' && ch<='9';ch=getchar())x=x*10+ch-'0';
21     if(f) x=-x;
22 }
23 int main()
24 {
25     read(n);read(k);
26     for(int i=1;i<=n;i++)
27     {
28         read(a[i]);l[i]=i-1;r[i]=i+1;
29         Q.push(Node(a[i],i));
30     }
31     ll ans=0;
32     for(int i=1;i<=k;i++)
33     {
34         while(vis[Q.top().id]) Q.pop();
35         Node now=Q.top();Q.pop();
36         if(now.val<0) break;
37         ans+=now.val;int p=now.id;
38         a[p]=a[l[p]]+a[r[p]]-a[p];
39         Q.push(Node(a[p],p));
40         vis[l[p]]=vis[r[p]]=1;
41         l[p]=l[l[p]];r[l[p]]=p;
42         r[p]=r[r[p]];l[r[p]]=p;
43     }
44     printf("%lld",ans);
45     return 0;
46 }
View Code

 

posted @ 2018-10-15 07:48  Oracle_LinJH  阅读(77)  评论(0编辑  收藏  举报