题意:一个长度为n的环,每个点有贡献,取了一个就不能取他的相邻,问取1-n/2个的最优方案是多少。
DP可能会挂,我自己试了试好像会出点问题= =毕竟是环,如果类似这种问题,不能拆环一般就不要DP。
于是考虑贪心,大根堆优化。其实这题可以算是堆优化贪心的典型例题了,每次取完堆顶以后把这个点的贡献改为这个点相邻的两个点的贡献-这个点的贡献,然后把相邻两个删掉,相当于再次取到这个点时就是撤销,就是把这个点去掉,然后选择相邻的两个点的贡献。因为涉及到动态删除,所以用链表维护。
注意开ll,被坑了QAQ。
luogu好像有一道差不多的题目,叫什么编译优化,就是没要求输出n/2次,所以那题水一点。。
#include<bits/stdc++.h>
using namespace std;
#define N 200010
#define LL long long
#define P make_pair
int n,t,l[N],r[N];
bool vis[N];
LL ans,a[N];
priority_queue< pair<LL,int> >q;
int input() {
int f=1,g=0; char c=getchar();
while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9') {g=g*10+c-'0';c=getchar();}
return f*g;
}
int main() {
freopen("cat.in","r",stdin);
freopen("cat.out","w",stdout);
n=input();
for(int i=1;i<=n;i++) a[i]=input(),q.push(P(a[i],i));
for(int i=1;i<=n;i++) l[i]=i-1,r[i]=i+1; l[1]=n,r[n]=1;
for(int i=1;i<=n/2;i++) {
while(vis[t=q.top().second]) q.pop();
ans+=q.top().first,q.pop();
vis[l[t]]=vis[r[t]]=1,a[t]=a[l[t]]+a[r[t]]-a[t];
l[t]=l[l[t]],r[t]=r[r[t]],r[l[t]]=l[r[t]]=t;
q.push(P(a[t],t)),printf("%lld\n",ans);
}
return 0;
}