题目大意:
给定一个大小为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 }